pwnhub无用的电脑_丧心病狂_writeup

比赛地址是 pwnhub.cn

也可以下载我上传的writeup来看

弱渣用的解法超奇怪233333333

然而居然还被选上了官方推荐

接下来看看正文吧


得到pwnhub.jar包,先跑起看看

java -jar pwnhub.jar

1

jar包好说,拖进jd-gui看看

结果出来一堆疑似MD5处理的类名,除了最后五个小写的类能正常反编译外,其余1500+个都不能正常打开

2

反编译看出,先验证code,code的长度为4,接着就是验证code的类

对应a4a89174426b40307102e165374ab8ab.class这个类,里面的验证代码略复杂

因为code只有4位,copy一下代码暴力跑下就出来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pwnhub.ConvertClass;

public class Test{

private static final char[] word = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray();

public static void main(String[] args) {
for(char a : word){
for(char b : word){
for(char c : word){
for(char d : word){
String tmp = String.valueOf(a)+String.valueOf(b)+String.valueOf(c)+String.valueOf(d);
if(ConvertClass.b(tmp)){
System.out.println(tmp);
}
}
}
}
}
}
}

//result: mdzz

跑出来code = mdzz

3

接下来就是输入flag验证了

跟踪到这个类中,发现通过java的反射机制加载checkFlag这个类

4

跟踪进去mc这个类,就能看到其中重载了ClassLoaderfindClass这个函数

通过MD5转换类名,找到对应类文件,并通过AES解密,秘钥写死,解密后获取对应的类

5


6

把类copy出来,并且在最后添加一段

1
2
3
4
5
6
7
8
9
10
11
12
//output the decoded file
//********************************my operation**************************
try {
FileOutputStream out = new FileOutputStream(name);
out.write(en, 0, en.length);
out.flush();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//********************************finish********************************

获取解密后的类

获得的checkFlag类

7

把b和flag的字节码传进函数中获取返回值验证

前面有个load.l()的函数,cadqa也不知道是什么类

但猜想可通过同样原理从一堆加密的class中把原来的类解密出来

获得cadqa类

1
2
GetClass mClass = new GetClass();
Class<?> clazz = mClass.findClass("pwnhub.cadqa");

8

y变换出下一个类名,同样通过反射机制获取下一个类

注意到对b[2]进行了一次异或操作,并继续传进下一个函数

同理copy出来获取下一个类pwnhub.wmyvg

会发现下一个类中也是差不多同样的东西

一直传递进去

好,所以换种思路,可以在开始重载的findClass函数中加进输出类名的信息,替换掉原jar包中的类,则可以输出逐步加载的类名

这里注意之前提到过的load.l()函数,通过findClass找到该类发现方法中把所有的类都加载了一遍

所以还需要做出一点修改

9

思路是: 修改checkFlag类,注释掉load.l()语句,注意到传进的int[] b在每次迭代的类中都对其中一位进行异或,每个中间的类只对该数组进行了修改,别的都无关,我们直接在最后输出最终的b数组的值,不必关注当中的过程。

修改checkFlag

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
package pwnhub;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

public class checkFlag {
public static void check() throws Exception {
// load.l();
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("ok, now give me flag");
System.out.print("flag:");
String flag = strin.readLine();

int[] b = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

byte[] result = cadqa.i(flag.getBytes(), b);

System.out.print("Array b: ");
for(int i : b){
System.out.print(i + ", ");
}

byte[] tFlag = { 16, 37, -54, -1, -36, -34, -83, -64, 39, -112, 5, -85, 61, 108, -4, 13, 85, -22, -116, -77, 31, 21, -64, 13, -86, -48, -86, -115, -28, -82, 48, -15 };
if (Arrays.equals(result, tFlag)) {
System.out.println("pwnhub{flag:" + flag + "}");
} else {
System.out.println("try again");
}
}
}

因为该类是通过AES解密出来的,替换原jar包中的该类必须先把类加密

对于java中AES的方法非常简单,因为秘钥已写死,只要把重写的findClass中的代码拷贝出来

因为

1
2
public static final int ENCRYPT_MODE = 1;
public static final int DECRYPT_MODE = 2;

所以在cipher.init(2, skey, iv);改为cipher.init(1, skey, iv);就加密出来了

输出加密后的类就可以替换原jar包中的类了

跑一下修改后的jar包

得到

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
102
103
104
105
106
107
108
no passcode, no game
code:mdzz
classname: checkFlag
ok, now give me flag
flag:aaaaaa
classname: cadqa
classname: wmyvg
classname: fthyl
classname: knklz
classname: swygk
classname: xbzvx
classname: bstqh
classname: lmvxj
classname: iaclf
classname: civgj
classname: jzlnc
classname: wpzay
classname: yhusg
classname: qrleu
classname: ryugj
classname: krvkv
classname: rysks
classname: mcnky
classname: pqxex
classname: hfdxm
classname: bhlro
classname: ghxxg
classname: kxgjk
classname: ugeia
classname: gxizy
classname: whpuy
classname: itjyb
classname: dypmm
classname: vphxl
classname: xmopd
classname: bkarw
classname: xwver
classname: qujkq
classname: jwzgx
classname: lpodr
classname: dfhcv
classname: uxxlh
classname: qkznr
classname: jovrk
classname: plmbn
classname: dnmoe
classname: lxmpw
classname: mvhaz
classname: ekuyu
classname: zqggw
classname: oxodn
classname: tjoao
classname: ytpej
classname: yjubo
classname: igjiv
classname: aaisy
classname: uvrut
classname: krdya
classname: rmrou
classname: tknxh
classname: gzmbz
classname: dkqcg
classname: zrhvo
classname: biosp
classname: ddbfz
classname: tdozs
classname: klfqs
classname: wtwpi
classname: icpbr
classname: angkn
classname: vjsqq
classname: lazus
classname: hjtcg
classname: jwuvs
classname: eximk
classname: qotct
classname: prlhh
classname: ictnz
classname: vdwrx
classname: akkks
classname: mtyvu
classname: ummng
classname: zltaa
classname: ptqro
classname: bdoqu
classname: iaedu
classname: ekjiz
classname: wzvnt
classname: uxxzo
classname: oshbc
classname: jfwqa
classname: ubvnq
classname: itlpk
classname: wwigc
classname: hnvij
classname: ctavm
classname: gsqdi
classname: wqeuz
classname: rjfog
classname: fkviz
classname: bjbwm
classname: gefao
classname: hllei
classname: wmolw
classname: herqz
classname: dlfnv
classname: frsu
try again

看待迭代了这么多个类……

并且跑出了最终b数组的值

1
int b[] = {187632156, 874189824, 254150144, 924386310, 121057538, 840500228, 389160971, 907870729, 389426184, 973875457, 372376604, 707731490, 1043334948, 439222784, 876216579, 455999525};

查看最后加载的两个类,类dlfnv是跟上面的一样的迭代类

最后的frsu是最终的解密类

同理获得解出来的类,得到一段复杂的代码

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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
static byte[] b(byte[] flag, int[] bInt) throws Exception {
int[] constantArr1 = { 943331329, 170788368, 1008414755, 187049985, 1010368540, 220604441, 940377620, 255209728,
689771012, 221709344, 957157408, 892536332, 722417666, 1026621720, 655302664, 890966315 };
int[] constantArr2 = { 1847617210, 1994607775, 1906299266, 1443467998, 1753140052, 782026644, 743697037, 1500018807,
1015162722, 141403752, 1057274701, 1430471406, 921937966, 1419221067, 962664086, 2133607337 };
for (int i = 0; i < 16; i++) {
bInt[i] ^= constantArr2[i];
}
int[] mergeBInt = new int[32];
for (int i = 0; i < 16; i++) {
mergeBInt[i] = constantArr1[i];
}
for (int i = 0; i < 16; i++) {
mergeBInt[(i + 16)] = bInt[i];
}
byte[] flagcp = flag;

int[] constantArr3 = { 16843776, 0, 65536, 16843780, 16842756, 66564, 4, 65536, 1024, 16843776, 16843780, 1024,
16778244, 16842756, 16777216, 4, 1028, 16778240, 16778240, 66560, 66560, 16842752, 16842752, 16778244,
65540, 16777220, 16777220, 65540, 0, 1028, 66564, 16777216, 65536, 16843780, 4, 16842752, 16843776,
16777216, 16777216, 1024, 16842756, 65536, 66560, 16777220, 1024, 4, 16778244, 66564, 16843780, 65540,
16842752, 16778244, 16777220, 1028, 66564, 16843776, 1028, 16778240, 16778240, 0, 65540, 66560, 0,
16842756 };
int[] constantArr4 = { -2146402272, -2147450880, 32768, 1081376, 1048576, 32, -2146435040, -2147450848, -2147483616,
-2146402272, -2146402304, Integer.MIN_VALUE, -2147450880, 1048576, 32, -2146435040, 1081344, 1048608,
-2147450848, 0, Integer.MIN_VALUE, 32768, 1081376, -2146435072, 1048608, -2147483616, 0, 1081344, 32800,
-2146402304, -2146435072, 32800, 0, 1081376, -2146435040, 1048576, -2147450848, -2146435072,
-2146402304, 32768, -2146435072, -2147450880, 32, -2146402272, 1081376, 32, 32768, Integer.MIN_VALUE,
32800, -2146402304, 1048576, -2147483616, 1048608, -2147450848, -2147483616, 1048608, 1081344, 0,
-2147450880, 32800, Integer.MIN_VALUE, -2146435040, -2146402272, 1081344 };
int[] constantArr5 = { 520, 134349312, 0, 134348808, 134218240, 0, 131592, 134218240, 131080, 134217736, 134217736,
131072, 134349320, 131080, 134348800, 520, 134217728, 8, 134349312, 512, 131584, 134348800, 134348808,
131592, 134218248, 131584, 131072, 134218248, 8, 134349320, 512, 134217728, 134349312, 134217728,
131080, 520, 131072, 134349312, 134218240, 0, 512, 131080, 134349320, 134218240, 134217736, 512, 0,
134348808, 134218248, 131072, 134217728, 134349320, 8, 131592, 131584, 134217736, 134348800, 134218248,
520, 134348800, 131592, 8, 134348808, 131584 };
int[] constantArr6 = { 8396801, 8321, 8321, 128, 8396928, 8388737, 8388609, 8193, 0, 8396800, 8396800, 8396929, 129, 0,
8388736, 8388609, 1, 8192, 8388608, 8396801, 128, 8388608, 8193, 8320, 8388737, 1, 8320, 8388736, 8192,
8396928, 8396929, 129, 8388736, 8388609, 8396800, 8396929, 129, 0, 0, 8396800, 8320, 8388736, 8388737,
1, 8396801, 8321, 8321, 128, 8396929, 129, 1, 8192, 8388609, 8193, 8396928, 8388737, 8193, 8320,
8388608, 8396801, 128, 8388608, 8192, 8396928 };
int[] constantArr7 = { 256, 34078976, 34078720, 1107296512, 524288, 256, 1073741824, 34078720, 1074266368, 524288,
33554688, 1074266368, 1107296512, 1107820544, 524544, 1073741824, 33554432, 1074266112, 1074266112, 0,
1073742080, 1107820800, 1107820800, 33554688, 1107820544, 1073742080, 0, 1107296256, 34078976, 33554432,
1107296256, 524544, 524288, 1107296512, 256, 33554432, 1073741824, 34078720, 1107296512, 1074266368,
33554688, 1073741824, 1107820544, 34078976, 1074266368, 256, 33554432, 1107820544, 1107820800, 524544,
1107296256, 1107820800, 34078720, 0, 1074266112, 1107296256, 524544, 33554688, 1073742080, 524288, 0,
1074266112, 34078976, 1073742080 };
int[] constantArr8 = { 536870928, 541065216, 16384, 541081616, 541065216, 16, 541081616, 4194304, 536887296, 4210704,
4194304, 536870928, 4194320, 536887296, 536870912, 16400, 0, 4194320, 536887312, 16384, 4210688,
536887312, 16, 541065232, 541065232, 0, 4210704, 541081600, 16400, 4210688, 541081600, 536870912,
536887296, 16, 541065232, 4210688, 541081616, 4194304, 16400, 536870928, 4194304, 536887296, 536870912,
16400, 536870928, 541081616, 4210688, 541065216, 4210704, 541081600, 0, 541065232, 16, 16384, 541065216,
4210704, 16384, 4194320, 536887312, 0, 541081600, 536870912, 4194320, 536887312 };
int[] constantArr9 = { 2097152, 69206018, 67110914, 0, 2048, 67110914, 2099202, 69208064, 69208066, 2097152, 0,
67108866, 2, 67108864, 69206018, 2050, 67110912, 2099202, 2097154, 67110912, 67108866, 69206016,
69208064, 2097154, 69206016, 2048, 2050, 69208066, 2099200, 2, 67108864, 2099200, 67108864, 2099200,
2097152, 67110914, 67110914, 69206018, 69206018, 2, 2097154, 67108864, 67110912, 2097152, 69208064,
2050, 2099202, 69208064, 2050, 67108866, 69208066, 69206016, 2099200, 0, 2, 69208066, 0, 2099202,
69206016, 2048, 67108866, 67110912, 2048, 2097154 };
int[] constantArr10 = { 268439616, 4096, 262144, 268701760, 268435456, 268439616, 64, 268435456, 262208, 268697600,
268701760, 266240, 268701696, 266304, 4096, 64, 268697600, 268435520, 268439552, 4160, 266240, 262208,
268697664, 268701696, 4160, 0, 0, 268697664, 268435520, 268439552, 266304, 262144, 266304, 262144,
268701696, 4096, 64, 268697664, 4096, 266304, 268439552, 64, 268435520, 268697600, 268697664, 268435456,
262144, 268439616, 0, 268701760, 262208, 268435520, 268697600, 268439552, 268439616, 0, 268701760,
266240, 266240, 4160, 4160, 262208, 268435456, 268701696 };
int flagLen = flagcp.length;
int var72 = flagLen % 8;
if (var72 != 0) {
System.out.println("try again");
System.exit(0);
}
var72 = 2;

int[] var21 = new int[var72];
byte[] var22 = new byte[flagLen];
int var23 = flagLen / 8; //2
int var24 = 0;
while (var24 < var23) {
int var25 = var24 * 8;

int var26 = 0;
//二进制{flag[0]flag[1]flag[2]flag[3]}构成var21[0]
//二进制{flag[4]flag[5]flag[6]flag[7]}构成var21[1]
while (var26 < 2) {
var21[var26] = ((flagcp[(var25 + var26 * 4)] & 0xFF) << 24
| (flagcp[(var25 + var26 * 4 + 1)] & 0xFF) << 16 | (flagcp[(var25 + var26 * 4 + 2)] & 0xFF) << 8
| flagcp[(var25 + var26 * 4 + 3)] & 0xFF);
var26++;
}
int var31 = 0;
int var29 = var21[0];
int var28 = var21[1];

int var27 = (var29 >>> 4 ^ var28) & 0xF0F0F0F;
var28 ^= var27;
var29 ^= var27 << 4;
var27 = (var29 >>> 16 ^ var28) & 0xFFFF;
var28 ^= var27;
var29 ^= var27 << 16;
var27 = (var28 >>> 2 ^ var29) & 0x33333333;
var29 ^= var27;
var28 ^= var27 << 2;
var27 = (var28 >>> 8 ^ var29) & 0xFF00FF;
var29 ^= var27;
var28 ^= var27 << 8;
var28 = var28 << 1 | var28 >>> 31 & 0x1;
var27 = (var29 ^ var28) & 0xAAAAAAAA;
var29 ^= var27;
var28 ^= var27;
var29 = var29 << 1 | var29 >>> 31 & 0x1;
int var30 = 0;
while (var30 < 8) {
var27 = var28 << 28 | var28 >>> 4;
var27 ^= mergeBInt[(var31++)];
var26 = constantArr9[(var27 & 0x3F)];
var26 |= constantArr7[(var27 >>> 8 & 0x3F)];
var26 |= constantArr5[(var27 >>> 16 & 0x3F)];
var26 |= constantArr3[(var27 >>> 24 & 0x3F)];
var27 = var28 ^ mergeBInt[(var31++)];
var26 |= constantArr10[(var27 & 0x3F)];
var26 |= constantArr8[(var27 >>> 8 & 0x3F)];
var26 |= constantArr6[(var27 >>> 16 & 0x3F)];
var26 |= constantArr4[(var27 >>> 24 & 0x3F)];
var29 ^= var26;
var27 = var29 << 28 | var29 >>> 4;
var27 ^= mergeBInt[(var31++)];
var26 = constantArr9[(var27 & 0x3F)];
var26 |= constantArr7[(var27 >>> 8 & 0x3F)];
var26 |= constantArr5[(var27 >>> 16 & 0x3F)];
var26 |= constantArr3[(var27 >>> 24 & 0x3F)];
var27 = var29 ^ mergeBInt[(var31++)];
var26 |= constantArr10[(var27 & 0x3F)];
var26 |= constantArr8[(var27 >>> 8 & 0x3F)];
var26 |= constantArr6[(var27 >>> 16 & 0x3F)];
var26 |= constantArr4[(var27 >>> 24 & 0x3F)];
var28 ^= var26;
var30++;
}
var28 = var28 << 31 | var28 >>> 1;
var27 = (var29 ^ var28) & 0xAAAAAAAA;
var29 ^= var27;
var28 ^= var27;
var29 = var29 << 31 | var29 >>> 1;
var27 = (var29 >>> 8 ^ var28) & 0xFF00FF;
var28 ^= var27;
var29 ^= var27 << 8;
var27 = (var29 >>> 2 ^ var28) & 0x33333333;
var28 ^= var27;
var29 ^= var27 << 2;
var27 = (var28 >>> 16 ^ var29) & 0xFFFF;
var29 ^= var27;
var28 ^= var27 << 16;
var27 = (var28 >>> 4 ^ var29) & 0xF0F0F0F;
var29 ^= var27;
var28 ^= var27 << 4;
var21[0] = var28;
var21[1] = var29;

int var32 = var24 * 8;
int var33 = 0;
//var22[0]var22[1]var22[2]var22[3]由var21[0]拆解得,对应变换后的flag[0]flag[1]flag[2]flag[3]
while (var33 < 2) {
var22[(var32 + var33 * 4)] = ((byte) (var21[var33] >>> 24));
var22[(var32 + var33 * 4 + 1)] = ((byte) (var21[var33] >>> 16));
var22[(var32 + var33 * 4 + 2)] = ((byte) (var21[var33] >>> 8));
var22[(var32 + var33 * 4 + 3)] = ((byte) var21[var33]);
var33++;
}
var24++;
}
byte var66 = var22[(var22.length - 1)];

return var22;
}

自己反推太复杂了,猜测是某种加密的算法

搜索关键的字符,发现这是DESEngine的代码

通过搜索得到的代码得知

通过generateWorkKey获得秘钥,加密秘钥与解密秘钥的关系非常大

秘钥为len = 32的int数组,其中

decKey[i] = encKey[30-i], decKey[i+1] = encKey[30-i+1], i=0,2,4,6...14

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int[] constantArr1 = { 943331329, 170788368, 1008414755, 187049985, 1010368540, 220604441, 940377620, 255209728, 689771012, 221709344, 957157408, 892536332, 722417666, 1026621720, 655302664, 890966315 };
int[] constantArr2 = { 1847617210, 1994607775, 1906299266, 1443467998, 1753140052, 782026644, 743697037, 1500018807, 1015162722, 141403752, 1057274701, 1430471406, 921937966, 1419221067, 962664086, 2133607337 };
for (int i = 0; i < 16; i++) {
bInt[i] ^= constantArr2[i];
}
int[] mergeBInt = new int[32];
for (int i = 0; i < 16; i++) {
mergeBInt[i] = constantArr1[i];
}
for (int i = 0; i < 16; i++) {
mergeBInt[(i + 16)] = bInt[i];
}
//------add-------
for(int i=0;i<16;i+=2){
int tmp = mergeBInt[30-i];
mergeBInt[30-i] = mergeBInt[i];
mergeBInt[i] = tmp;

tmp = mergeBInt[30-i+1];
mergeBInt[30-i+1] = mergeBInt[i+1];
mergeBInt[i+1] = tmp;
}
//----add finish---

前面加入一段代码就能变为解密的函数

这里还有点得注意的,因为在传进函数后有这么一段

1
2
3
for (int i = 0; i < 16; i++) {
bInt[i] ^= constantArr2[i];
}

所以输出的b数组是异或后的结果。

解密时先异或回来再传进函数解密

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
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, UnsupportedEncodingException {

int b[] = {187632156, 874189824, 254150144, 924386310, 121057538, 840500228, 389160971, 907870729, 389426184, 973875457, 372376604, 707731490, 1043334948, 439222784, 876216579, 455999525};

int[] constantArr2 = { 1847617210, 1994607775, 1906299266, 1443467998, 1753140052, 782026644, 743697037, 1500018807, 1015162722, 141403752, 1057274701, 1430471406, 921937966, 1419221067, 962664086, 2133607337 };
for(int i=0;i<b.length;i++){
b[i] ^= constantArr2[i];
}

String flag = null;
byte[] tFlag = {16, 37, -54, -1, -36, -34, -83, -64, 39, -112, 5, -85, 61, 108, -4, 13, 85, -22, -116, -77, 31, 21, -64, 13, -86, -48, -86, -115, -28, -82, 48, -15 };
byte[] result = null;
try {
result = frsu.decode(tFlag, b);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i = 0;i<result.length;i++){
System.out.print(result[i] + ", ");
}
System.out.println();

flag = new String(result);
System.out.println(flag);

}

即可跑出3c5ab398eb3bcb8e829126f5ae60442b

并验证成功

1
2
3
4
5
no passcode, no game
code:mdzz
ok, now give me flag
flag:3c5ab398eb3bcb8e829126f5ae60442b
pwnhub{flag:3c5ab398eb3bcb8e829126f5ae60442b}

×

赞助gif换电脑、吃双皮奶(逃

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
,