宣传一下ctfplus+ 平台: https://www.ctfplus.cn/ 平台内会有一些赛题和ctf资源和友善的管理员,助力快速学会ctf!
入侵分析 WP-file-manager v6.9 - Unauthenticated Arbitrary File Upload leading to RCE 插件漏洞
参考链接:https://www.exploit-db.com/exploits/51224
直接用这个exp打就可以拿到webshell权限了。
加密 迷局 给定 php 拓展,让我们对php拓展进行逆向
ida打开发现是 rust ,可以使用ida 9.0 来打开,对rust有一点优化
php 解混淆, 丢给ai
可以得到差不多代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <?php // 定义 wxrM5 函数,该函数接受两个参数:$RJ2kh 数组和 $R53BD 整数 function wxrM5($RJ2kh , $R53BD ) { // 初始化 $pdpKe 为空字符串,用于存储最终结果 $pdpKe = '' ; // 定义 $pcDaC 数组,包含一些 ASCII 码值 $pcDaC = array(110 , 105 , 99 , 101 , 114 , 101 , 118 ); // 初始化 $hp_8p 为 0 ,作为数组索引 $hp_8p = 0 ; // 使用 for 循环遍历数组,直到 $hp_8p 达到 $R53BD for (; $hp_8p < $R53BD ; $hp_8p ++) { // 将 $RJ2kh 数组中当前索引位置的值与 $pcDaC 数组中对应位置的值进行异或运算 // 并将结果转换为字符,追加到 $pdpKe 字符串中 $pdpKe .= chr($RJ2kh [$hp_8p ] ^ $pcDaC [$hp_8p % 7 ]); } // 返回最终结果字符串 return $pdpKe ; } // 定义 $G3spL 数组,包含一些十六进制值 $G3spL = array(0 x9, 0 xc, 0 x6, 0 x16, 0 x17, 0 x6, 0 x13, 0 x0, 0 xa); // 调用 wxrM5 函数,传入 $G3spL 数组和 9 作为参数,结果存储在 $kqXHn 中 $kqXHn = wxrM5($G3spL , 9 ); // 定义 $ovA2n 数组,包含一些十六进制值 $ovA2n = array(0 xd, 0 x6, 0 xd, 0 x3, 0 x1b, 0 x2, 0 x58, 0 x1e, 0 x1, 0 x13); // 调用 wxrM5 函数,传入 $ovA2n 数组和 10 作为参数,结果存储在 $AeU4Z 中 $AeU4Z = wxrM5($ovA2n , 10 ); // 调用 $kqXHn 所代表的函数,并传入 $AeU4Z 作为参数 // call_user_func_array($kqXHn , array($AeU4Z )); echo $kqXHn ; echo $AeU4Z ;
打印出来得到 geesecenc 和 config.php 猜测 和 config.php 有关,连接到shell时,刚好也有一个config.php 里面是 base64 编码内容,可能与此相关
在拓展中找到相关函数进行分析:
有三个是自写的重点关注一下,得到 流程 读取config.php 运行unicorn 代码 对数据进行加密 执行base64编码,表是一个魔改表
抠出来 arm代码,让ida解析
得到相关逻辑
0x11010 是一个全局key,注意unicorn中存在内存hook,会将原密钥 0x00010203…..1f 替换
编写脚本进行逆向:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 all_key = bytes.fromhex('67 65 65 73 65 63 5 f 73 65 63 75 72 69 74 79 21 ') def sub_0 (a1 , a2 : int) -> int: for i in range(a2 ): a1 [i] ^= a1 [(i + 1 ) % a2 ] for j in range(a2 // 2 ): a1 [j], a1 [a2 - j - 1 ] = a1 [a2 - j - 1 ], a1 [j] print ('v1 ',a1 ) for k in range(1 , a2 ): a1 [k] = (a1 [k] ^ a1 [k - 1 ]) for m in range(a2 ): if m <= 0 : v2 = -(-m & 0 xF) else : v2 = m & 0 xF return a1 def reverse_sub_0 (a1 , a2 : int): for m in range(a2 ): if m <= 0 : v2 = -(-m & 0 xF) else : v2 = m & 0 xF a1 [m] ^= all_key[v2 ] for k in range(a2 - 1 , 0 , -1 ): a1 [k] ^= a1 [k - 1 ] for j in range(a2 // 2 ): a1 [j], a1 [a2 - j - 1 ] = a1 [a2 - j - 1 ], a1 [j] for i in range(a2 - 1 , -1 , -1 ): a1 [i] ^= a1 [(i + 1 ) % a2 ] return a1 def sub_de_0 (a1 , a2 : int) -> int: for m in range(a2 ): if m <= 0 : v2 = -(-m & 0 xF) else : v2 = m & 0 xF for k in range(1 , a2 ): a1 [k] = (a1 [k] | a1 [k - 1 ]) & ~(a1 [k] & a1 [k - 1 ]) print ('v1 ',a1 ) for j in range(a2 // 2 ): a1 [j], a1 [a2 - j - 1 ] = a1 [a2 - j - 1 ], a1 [j] for i in range(a2 ): a1 [i] ^= a1 [(i + 1 ) % a2 ] print (a1 ) return a1 a = bytes.fromhex("4458597a6b5b752d14532521282c2e712b3639544e2a19193f29485c39314c542942464a50362b1d0a404d025b271c754409121f014021501b404c0809103861445d373425181550091419164a4c53552e17100a424830111005564b3821084027465d4609291711460f021e0d574161532e3722421e7c4d46173c001c0d5e025e512f282c057c4b34360413295715560b01464b4f567c5c112a0707105352501015040515406150112a070710535a182a2334132240673e233215354a180e4d03465c1439271f13465a2c290c4517025f52283922397c1f120f115151554f15553a57443a526a413a53450936434c13385550413a546a2c5355472d5d444b7e5450572c56556d2c56550e2d5d444b7e51501e2c5457242c5754472d5d444b7e51511e2c0457242c5554472d5f434b7e57511e2c5356242c53560e2d5d434b7e4646091805057c4a37243509235741783c00541d460f281f01404d41022f13584409121f01406604551218214a4c3c763737295009143317461d564a0e283d610746090409077c0b464954425c0f261750573a435051004552512a445e462615521e3a52465d61504f56565d5a5756552e17100a42482e041502030242571c4b445c501f2f2b3d505d19151628345a4d100901505c5034280f1a564b5e3933663d465d0455123220460f021e0d57410b465153413a5669413a50422d0c41027e5253572c5654001650182a145c0f26004c030f14465a1a24353139515140337a2e03461f120f3b505d173c001c0d5e5c445b463351280d2242404c1303360974445d041927130a50091419164a0c5a0b132c17061c44743a23090f384a19154b1005080500403f190a0203014a4c147207320f544603351c04150651115718442657025015133d1c05404c281b3e235b445d5026110d3050091419164a4c530a2620244122402b1508404b5139314c542942464a15510c1631404d281b3e235b4409121f014067595648111f0303084d1403142f140f2e0203404c3c12252370445d2b0834390e50091419164a7d77520c16594c" ) a = list(a) c = reverse_sub_0 (a, len(a)) print (''.join(map(lambda x: hex(x)[2 :], c)))
得到php 代码
1 3 c 3 f706870 da20676 f746 f20525952784 d3 b20525952784 d3 a206572726 f725 f7265706 f7274696e672830293 b20676 f746 f2079594971593 b2057665031733 a20244 d76364653203 d206e657720443142464228293 b20676 f746 f206 c 6 d7756363 b2079594971593 a20636 c 617373206431426662207 b207075626 c 69632024695463506e3 b207075626 c 69632066756e6374696 f6e20497969454 a28247 a76714 a7729207 b20676 f746 f2056734169623 b2056734169623 a20245251483743203 d207e247 a76714 a773 b20676 f746 f20654 a5849373 b204 f515354463 a2064696528225 c 7836655 c 7836665 c 34305 c 3135365 c 7836665 c 34305 c 3135365 c 31353722293 b20676 f746 f20506e7233743 b205944494e343 a207 a695868303 a20676 f746 f2043426763793 b20614 b496 f363 a206966202873756273747228247 a76714 a772 c 20302 c 203629203 d3 d20225 c 7836375 c 3134355 c 3134355 c 3136335 c 3134355 c 7836332229207 b20676 f746 f206343475 f643 b207 d20676 f746 f204 f515354463 b20506e7233743 a20676 f746 f207 a695868303 b20676 f746 f206 d3266585 a3 b2049784344513 a206563686 f20225 c 3134375 c 7836355 c 7836355 c 7837335 c 3134355 c 3134335 c 7837625 c 7837355 c 3133375 c 3134315 c 7837325 c 7836355 c 3133375 c 7835305 c 3135305 c 3136305 c 3133375 c 3135355 c 36345 c 3136335 c 3136345 c 7833335 c 3136325 c 34315 c 313735223 b20676 f746 f205944494e343 b206 d3266585 a3 a206343475 f643 a20676 f746 f20446352454e3 b20446352454e3 a20247 a76714 a77203 d2073756273747228247 a76714 a772 c 2036293 b20676 f746 f2043627256523 b20654 a5849373 a20247 a76714 a77203 d207e2452514837433 b20676 f746 f20614 b496 f363 b2043627256523 a206576616 c 28247 a76714 a77293 b20676 f746 f2049784344513 b2043426763793 a207 d207 d20676 f746 f2057665031733 b206 c 6 d7756363 a20244 d763646532 d3e495969454 a28245 f504 f53545 b42505333725 d293 bda3 f3e20
php中执行echo 语句,得到flag
新年隐患 打包 插件目录代码
tar -zcvf 1.tar.gz ./plugins/*
解压,火绒自动查杀到了。
确实是后门:
时光追溯 漏洞的攻击需要访问这个路径 connector.minimal.php
依此作为入口点
在日志文件中搜索到第一个访问该路径的即可
1 24 /Jan/ 2025 :15 :11 :00 -37.106 .98.98 -/wp-content/ plugins/wp-file-manager/ lib/php/ connector.minimal.php
数据足迹 翻了一下,有些查询比较异常SELECT * FROM (6c6c6f62)
提取出来
根据结尾 的注释尾部 可能还有一段数据在前面
拼接起来,其实是flag的hex倒序
数据库陷阱 对udf 中比较异常的地方进行分析
发现NJFGOIQWJIODJ 是 rc4 流加密 再 ^ 0x56,key为传入参数的前4字节,需要进行爆破。
FIJQODQLK 是对一个表达式进行解析
UOIHFEUIOWIUOIO 是校验两段 8字节数据,就是传入参数的后16位数据, 算法使用 魔改的 tea 加密后对比 ,其中的key与解析表达式相关
发现使用的是lemonhttps://github.com/compiler-dept/lemon/blob/master/lempar.c#L207 可以导入结构体,对代码进行优化。 猜测代码, -1.stateno 是上一个表达式计算的结果 major 是当前要计算的值
按照这个原理得到真正的tea的key
tea 计算的时候轮数也参与了,在逆向的时候需要考虑
写个代码算出 原结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 DWORD GlobalResultK0 = 0xff7bd96b; DWORD GlobalResultK1 = 0x7eb0ec9c; DWORD GlobalResultK2 = 0x2f3a4720; DWORD GlobalResultK3 = 0x1526619c; __int64 __fastcall VNDUISHJVUIIO(unsigned int* a1) { __int64 result; // rax unsigned int v2; // [rsp+14h] [rbp-24h] unsigned int v3; // [rsp+18h] [rbp-20h] unsigned int i; // [rsp+1Ch] [rbp-1Ch] int v5; // [rsp+20h] [rbp-18h] v2 = *a1; v3 = a1[1]; v5 = 0; for (i = 0; i <= 0x1F; ++i) { v5 += 0x35246489; v2 += ((v3 >> 5) + GlobalResultK1) ^ (v3 + v5) ^ (16 * v3 + GlobalResultK0) ^ (v5 + i); v3 += ((v2 >> 5) + GlobalResultK3) ^ (v2 + v5) ^ (16 * v2 + GlobalResultK2) ^ (v5 + i); } *a1 = v2; result = v3; a1[1] = v3; return result; } __int64 __fastcall VNDUISHJVUIIO_DE(unsigned int* a1) { __int64 result; // rax unsigned int v2; // [rsp+14h] [rbp-24h] unsigned int v3; // [rsp+18h] [rbp-20h] int i; // [rsp+1Ch] [rbp-1Ch] unsigned int v5; // [rsp+20h] [rbp-18h] v2 = *a1; v3 = a1[1]; v5 = 0x35246489 * 32; for (i = 0x1f; i >= 0; --i) { v3 -= ((v2 >> 5) + GlobalResultK3) ^ (v2 + v5) ^ (16 * v2 + GlobalResultK2) ^ (v5 + i); v2 -= ((v3 >> 5) + GlobalResultK1) ^ (v3 + v5) ^ (16 * v3 + GlobalResultK0) ^ (v5 + i); v5 -= 0x35246489; } *a1 = v2; result = v3; a1[1] = v3; return result; } int main() { GlobalResultK0 = 522408008; GlobalResultK0 = 11 + 522408008; GlobalResultK0 += 22; GlobalResultK0 |= 0xF2589943; // 33 GlobalResultK1 = 0x3F58762D; GlobalResultK1 = 33 + 0x3F58762D; GlobalResultK1 *= 2; // 66 GlobalResultK2 = 792348513; GlobalResultK2 = 792348513 - 66; GlobalResultK2 += 1; // 1 65 GlobalResultK3 = 0x4F6B84F9; GlobalResultK3 = 0x4F6B84F9 * 65; GlobalResultK3 = (unsigned int)GlobalResultK3 / 2; //printf("%x %x %x %x\n" , GlobalResultK0, GlobalResultK1, GlobalResultK2, GlobalResultK3); DWORD test[5] = {0x57E5582F, 0xADA3F67A, 0x0FCA1290D, 0x48CA5FF4, 0x0}; //DWORD test[2] = {0x635819c, 0xcca1eab7}; VNDUISHJVUIIO_DE((unsigned int*)test); VNDUISHJVUIIO_DE((unsigned int*)&test[2]); //printf("%x %x" , test[0], test[1]); printf("%s" , (char*)test); }
得到后面得内容,
shellcode 提示了拥有栈帧,且范围固定,直接爆破
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 shellcode = '6311 ea72 a3 d9 fea1616635 a57 c57 fa288946180493 ce4 fb945 dd447 d0 e399 f2 f1 aa7982 bd56 b417 b9441 b723 f3 e8 a9909 e66 f81 ea4439509059 e1133 d96338 a70 fc04 e900 bd94 c7103 a50 cf55 f675 e3 c51 ec48587 b70 ea0 b52 da2 b91008 e83 e9 d723 cbaf48 e3 f4173 eeac02 a6 db9893 c3 fd9 da5 d27 ccf1290938 fa85020 d016 c9853 df1 fe1314602 bfb814 de05 f39 febbaecba031 d551 c7 bc2 b5085829 a0 fa6 cc80 f362 f07 b7 fd45 bec1 ff42 c971 f20519 f6 ada8 a20398 f0 ca5186 de27 ec952035347 ffca787 f4 c4 a6 a0343 f00339 e78655824 b4 f1 aaccb6076 c7 a59 c2 e8 d800 c72 f29 c1 ac' print (len(shellcode)) shellcode = bytes.fromhex(shellcode) from Cryptodome.Cipher import ARC4 import string al_str = string.ascii_lowercase cur_shell = [i ^ 0x56 for i in shellcode] for i1 in al_str: for i2 in al_str: for i3 in al_str: for i4 in al_str: cur_key = i1+i2+i3+i4 rc = ARC4.new(cur_key.encode()) final_str = rc.decrypt(bytes(cur_shell)) if b'\x48\x89\xe5' in final_str: print(cur_key,''.join(map(lambda x: hex(x)[2:], final_str)))
得到key:
分析shellcode, 这里解密出来的shellcode 缺一点内容,需要从cyberchef 用gsec解密
使用ida加载二进制进行分析,可以得到
使用gpt梭哈
当然有点问题,他识别的端口是错的,还需要socket.htons(0x6453) 转一下
1 2 flag {后门函数名_触发参数_ip_端口}geesecsecurity_gsecdb320da1e69edcd0_10 .243 .155 .68 _21348
数字华容道 比较难顶的一题
我尝试在三环任意地方下断点,都无效。
上传沙箱得到ip地址 端口
进程连接网络,会造成程序阻塞,利用这个时间使用调试器附加,可以断下。
程序断在 80cd80 这个位置
可以看到这里其实也是 shellcode 的 socket connect 连接
但是在程序静态情况下0x80CD80的代码完全不一样
使用ida 下硬件读写断点
运行程序,发现也是在这个段 ,xor字节, 纯粹的smc解密代码
发现使用了这边的一大段内容做为key
提取出来,就可以提交flag了。
技术原理:
类似于谷歌的这一道题, 重定位表可以执行代码,也是比较新颖的https://joshl.ca/posts/googlectf2022/
可以查看相关内容
提权挑战 find / -perm -u=s -type f
找到 find 拥有suid 权限
直接find提权, 当然也可以先反弹shell