picoCTF - re - OTP Implementation

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中的输出包含了报错。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容