-
-
[原创]通过汇编“翻译”的PHP脚本爆破签到题
-
发表于: 2021-11-20 23:20 2482
-
1 2 3 4 5 6 7 8 | 工具 OllyDbg IDA PHP 题目用户名、序列号 用户名 : 01F845C5B7C52E56 序列号 : 653259165 [ 0x26EFF19D ] |
先用题目的用户名和序列号执行一次
关键提示语是Success!,OllyDbg加载程序,搜索字符串“Success!”可以看到程序最后是比较了eax跟一个常数值然后跳转的,不想等的时候跳转到了提示错误的地方。
那么关键值就是003A144F处的eax值。
通过在图例的这些位置打断点用题目用户名和序列号调试,摸清大概流程
a. 用户名及其长度通过kctf2021.003A1260计算得一个整数
b.得到结果0x744E1CC7
c. 序列号653259165(0x26EFF19D)与之前的计算结果0x744E1CC7按位异或
d. 得到结果0x52A1ED5A
e. 经过kctf2021.003A42B3处理转换为了字符串“52A1ED5A”
后边就简单了,字符串”52A1ED5A”及其长度8再次传入kctf2021.003A1260,计算结果整数与常量比较CMP EAX,13B88C77
以上过程伪代码:
1 2 3 4 5 6 7 8 | username, pass intRet = f003A1260(username, strlen(username)) intRet2 = intRet ^ intval( pass ) str = hex2str(intRet2) intRet3 = f003A1260( str , strlen( str )) if (intRet3 = = 13B88C77 ) { "Success!" } |
可以看出函数f003A1260为关键,解析来我们看一下kctf2021.003A1260
执行了1次以上过程
后续有7次执行过程,但是逻辑都相同,总结为执行了7次以上过程
最终计算值放到一个数组,然后比较计数器与0x100,如果小于则跳回loc_401275重复操作。
以上过程我们根据阅读的注释,翻译为PHP脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?php $seed = []; for ($ecx = 0 ; $ecx < 0x100 ; $ecx + + ) { $v = $ecx; $v = $v >> 1 ; if (! lastNot1($ecx)) { $v = xor0EDB88320($v); / / $v ^ 0x0EDB88320 ; } for ($i = 0 ; $i < 7 ; $i + + ) { if (!lastNot1($v)) { $v = $v >> 1 ; $v = xor0EDB88320($v); / / $v ^ 0x0EDB88320 ; } else { $v = $v >> 1 ; } } $seed[] = $v; } |
初始化ecx,遍历传入的字符串,检测长度,字符串逐字符计算。
取反,返回。可以看出其中计算数组的部分没有参数参与,每次都是同样的值,所以我们抽出这部分。整个函数最终封装为:
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 | function f003A1260($ str ) { global $seed; / / 公共数组seed $ecx = 0x100 ; / / 计算arr便利完就是 0x100 $ecx = or32($ecx, 0x0FFFFFFFF ); $end = strlen($ str ); for ($i = 0 ; $i < $end; $i + + ) { $c = $ str [$i]; $eax = ord ($c); / / var_dump($eax); $eax = xor32($eax, $ecx); $ecx = shr8($ecx); $eax = low8($eax); $ecx = xor32($ecx, $seed[$eax]); } $ret = ~$ecx; $b = decbin($ret); $b = substr($b, - 32 ); $b = bindec($b); return $b; } |
结合上述伪代码,我们做一个爆破脚本s1.php,存入~/bin/s1.php,通过php ~/bin/s1 test来测试题目中的用户名和序列号,通过以下三组来通过猜测的数字区间爆破。
1 2 3 | php ~ / bin / s1.php 0 php ~ / bin / s1.php 1 php ~ / bin / s1.php 2 |
文件内容如下:
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 | <?php / / link : https: / / ctf.pediy.com / game - season_fight - 180.htm $seed = []; for ($ecx = 0 ; $ecx < 0x100 ; $ecx + + ) { $v = $ecx; $v = $v >> 1 ; if (! lastNot1($ecx)) { $v = xor0EDB88320($v); / / $v ^ 0x0EDB88320 ; } for ($i = 0 ; $i < 7 ; $i + + ) { if (!lastNot1($v)) { $v = $v >> 1 ; $v = xor0EDB88320($v); / / $v ^ 0x0EDB88320 ; } else { $v = $v >> 1 ; } } $seed[] = $v; } function f003A1260($ str ) { global $seed; / / 公共数组seed $ecx = 0x100 ; / / 计算arr便利完就是 0x100 $ecx = or32($ecx, 0x0FFFFFFFF ); $end = strlen($ str ); for ($i = 0 ; $i < $end; $i + + ) { $c = $ str [$i]; $eax = ord ($c); / / var_dump($eax); $eax = xor32($eax, $ecx); $ecx = shr8($ecx); $eax = low8($eax); $ecx = xor32($ecx, $seed[$eax]); } $ret = ~$ecx; $b = decbin($ret); $b = substr($b, - 32 ); $b = bindec($b); return $b; } function reschk($ pass , $b) { $ pass = decbin(intval($ pass )); $ pass = substr($ pass , - 32 ); $ pass = bindec($ pass ); $cc = xor32($ pass , $b); / / 52A1ED5A $ hex = dechex($cc); $ len = 8 ; $reschk = f003A1260($ hex ); if ($reschk = = 330861687 ) { echo '正确的密钥' . PHP_EOL; return true; } return false; } function shr8($v) { $v = $v >> 8 ; $b = decbin($v); $b = substr($b, - 32 ); return bindec($b); } function or32($a, $b) { $c = $a | $b; $b = decbin($c); $b = substr($b, - 32 ); return bindec($b); } function xor32($a, $b) { $c = $a ^ $b; $b = decbin($c); $b = substr($b, - 32 ); return bindec($b); } function xor8($a, $b) { $c = $a ^ $b; $b = decbin($c); $b = substr($b, - 8 ); return bindec($b); } function lastNot1($ch) { $b = decbin($ch); $ bin = substr($b, - 1 ); return !($ bin = = '1' ); } function xor0EDB88320($v) { return xor32($v, 0x0EDB88320 ); } function low8($ch) { $b = decbin($ch); $ bin = substr($b, - 8 ); $h = bindec($ bin ); return $h; } function test() { $ str = '01F845C5B7C52E56' ; $b = f003A1260($ str ); if ($b = = 1951276231 ) { echo '正确' ; } else { echo '错误' ; } $ pass = '653259165' ; $r = reschk($ pass , $b); if ($r) { echo 'yes' . PHP_EOL; } } if (isset($argv[ 1 ]) && $argv[ 1 ] = = 'test' ) { test();exit; } $username = 'KCTF' ; $b = f003A1260($username); $arr = [ [ 153259165 , 353259165 ], / / 最终这个区间跑出了正确值 205824534 [ 353259165 , 430861687 ], [ 430861687 , 653259165 ], ]; $s = isset($argv[ 1 ]) ? intval($argv[ 1 ]) : 0 ; $start = $arr[$s][ 0 ]; $end = $arr[$s][ 1 ]; for ($i = $start; $i < $end; $i + + ) { if ($i = = $start + ceil(($end - $start) / 2 )) { echo '一半了' . PHP_EOL; } $r = reschk($i, $b); if ($r) { echo '最终' . PHP_EOL; var_dump($i);exit; } } echo '没有结果' . PHP_EOL; ?> |
最终第2组爆得一个结果:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)