main函数逻辑为:
undefined8 main(int argc,undefined8 *argv)
{
char cVar1;
byte bVar2;
int isValid;
undefined8 ret;
long in_FS_OFFSET;
int i;
int j;
char buf [100];
undefined local_84;
char local_78 [104];
long canary;
canary = *(long *)(in_FS_OFFSET + 0x28);
if (argc < 2) {
printf("USAGE: %s [KEY]\n",*argv);
ret = 1;
}
else {
strncpy(buf,(char *)argv[1],100);
local_84 = 0;
i = 0;
while( true ) {
isValid = valid_char((int)buf[i]);
if (isValid == 0) break;
if (i == 0) {
cVar1 = jumble();
bVar2 = (byte)(cVar1 >> 7) >> 4;
local_78[0] = (cVar1 + bVar2 & 0xf) - bVar2;
}
else {
cVar1 = jumble();
bVar2 = (byte)((int)cVar1 + (int)local_78[i + -1] >> 0x37);
local_78[i] = ((char)((int)cVar1 + (int)local_78[i + -1]) + (bVar2 >> 4) & 0xf) -
(bVar2 >> 4);
}
i += 1;
}
for (j = 0; j < i; j += 1) {
local_78[j] = local_78[j] + 'a';
}
if (i == 100) {
isValid = strncmp(local_78,
"bajbgfapbcclgoejgpakmdilalpomfdlkngkhaljlcpkjgndlgmpdgmnmepfikanepopbapfkdg leilhkfgilgabldofbcaedgfe"
,100);
if (isValid == 0) {
puts("You got the key, congrats! Now xor it with the flag!");
ret = 0;
goto LAB_001009ea;
}
}
puts("Invalid key!");
ret = 1;
}
LAB_001009ea:
if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
__stack_chk_fail();
}
return ret;
}
从对输入加密的逻辑可以得知,加密后数组中每一元素都会受前面元素的影响:
local_78[i] = ((char)((int)cVar1 + (int)local_78[i + -1]) + (bVar2 >> 4) & 0xf) -
(bVar2 >> 4);
看了很多别人的WP,利用ltrace可以从开头一字节一字节的爆破出密码。但很麻烦的是对ltrace和python的subprocess很不熟悉,写的过程碰了很多次壁,最后的exp为:
import subprocess
import re
from pwn import unhex, xor
flag = "ffadccb05b5892418ff068dd9d42231e8caf8ebb289ea1873f0a474cabe7ce598db77bac9dfef1d7c2b5af3c35bf5844c082"
enc = "bajbgfapbcclgoejgpakmdilalpomfdlkngkhaljlcpkjgndlgmpdgmnmepfikanepopbapfkdgleilhkfgilgabldofbcaedgfe"
key = ["0"] * 100
for i in range(100):
for j in "0123456789abcdef":
key[i] = j
p = subprocess.Popen(["ltrace", "-s", "1000", "./otp", "".join(key)],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
brute = re.findall(r"strncmp\(\"(.*?)\".*\)",
p.communicate()[0].decode())[0]
print(brute)
if brute[i] == enc[i]:
break
print(xor(unhex("".join(key)), unhex(flag)))
stdout需重定向到管道,否则communicate接收到的数据类型为NoneType,而且stderr也应重定向到stdout,因为ltrace中的输出包含了报错。