1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1日1CTFAdvent Calendar 2024

Day 6

former-seccomp (SECCON Beginners CTF 2024) WriteUp

Last updated at Posted at 2024-12-05

はじめに

この記事は 1日1CTF Advent Calendar 2024 の 6 日目の記事です。

問題

former-seccomp (問題出典: SECCON Beginners CTF 2024)

フラグチェック用のシステムコールを自作してみました

リポジトリ: https://github.com/SECCON/SECCON_Beginners_CTF_2024/tree/main/reversing/former-seccomp

考察

ghidra でデコンパイルして、本質を頑張って探すと、この関数っぽい。


undefined8 FUN_00101737(char *param_1)

{
  size_t sVar1;
  undefined8 uVar2;
  long lVar3;
  ulong local_28;
  long local_20;
  
  sVar1 = strlen(param_1);
  if (sVar1 == 0x1a) {
    for (local_28 = 0; sVar1 = strlen(&DAT_00104030), local_28 < sVar1; local_28 = local_28 + 1) {
      (&DAT_00104030)[local_28] = (char)local_28 + 0x20U ^ (&DAT_00104030)[local_28];
    }
    lVar3 = FUN_00101497(&DAT_00104010,&DAT_00104030);
    for (local_20 = 0; (param_1[local_20] != '\0' && (*(char *)(local_20 + lVar3) != '\0'));
        local_20 = local_20 + 1) {
      if (param_1[local_20] != *(char *)(local_20 + lVar3)) {
        return 0;
      }
    }
    uVar2 = 1;
  }
  else {
    uVar2 = 0;
  }
  return uVar2;
}

頑張って人力で読みやすくすると、こうなる。

int check(char *inp){
    int inp_len = strlen(inp);
    if(inp_len == 0x1a) {
        for(byte i = 0;i < strlen(key); i++) {
            key[i] = (i + 0x20U) ^ key[i];
        }
        byte *res = FUN_00101463();
        for(int i = 0; (inp[i] != '\0' && (res[i] != '\0')); i++) {
            if(inp[i] != res[i]) {
                return 0;
            }
        }
        return 1;
    }
    else {
        return 0;
    }
}

入力の長さが 0x1a か確認して、 FUN_00101497() 関数でフラグを生成して、入力と比較している。

FUN_00101497() 関数も見てみる。

void * FUN_00101497(char *param_1,char *param_2)

{
  size_t __size;
  void *pvVar1;
  size_t sVar2;
  long in_FS_OFFSET;
  ulong local_158;
  ulong local_150;
  ulong local_148;
  ulong local_140;
  ulong local_138;
  ulong local_130;
  byte local_118 [264];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __size = strlen(param_1);
  pvVar1 = malloc(__size);
  sVar2 = strlen(param_2);
  for (local_158 = 0; local_158 < 0x100; local_158 = local_158 + 1) {
    local_118[local_158] = (byte)local_158;
  }
  local_148 = 0;
  for (local_150 = 0; local_150 < 0x100; local_150 = local_150 + 1) {
    local_148 = (ulong)((int)param_2[local_150 % (ulong)(long)(int)sVar2] +
                        (uint)local_118[local_150] + (int)local_148 & 0xff);
    FUN_00101463(local_118 + local_150,local_118 + local_148);
  }
  local_140 = 0;
  local_138 = 0;
  for (local_130 = 0; local_130 < __size; local_130 = local_130 + 1) {
    local_140 = (ulong)((int)local_140 + 1U & 0xff);
    local_138 = (ulong)((int)local_138 + (uint)local_118[local_140] & 0xff);
    FUN_00101463(local_118 + local_140,local_118 + local_138);
    *(byte *)(local_130 + (long)pvVar1) =
         local_118[(int)(uint)(byte)(local_118[local_138] + local_118[local_140])] ^
         param_1[local_130];
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return pvVar1;
}

これも頑張って人力で直す。

byte * sub_check(){
    byte buf[264];
    long local_10;

    int dat_len = strlen(dat);
    byte *res = malloc(dat_len);

    int key_len = strlen(key);
    for(int i = 0; i < 0x100; i++) {
        buf[i] = i;
    }
    byte t = 0;
    for(int i = 0; i < 0x100; i++) {
        t = (key[i % key_len] + buf[i] + t) & 0xff;
        FUN_00101463(&buf[i],&buf[t]);
    }
    byte x = 0,y = 0;
    for(int i = 0; i < dat_len; i++) {
        x = (x + 1) & 0xff;
        y = (y + buf[x]) & 0xff;
        FUN_00101463(&buf[x],&buf[y]);
        res[i] = buf[(buf[y] + buf[x]) & 0xff] ^ dat[i];
    }

    return res;
}

途中で FUN_00101463() 関数が呼ばれているが、これは swap してるだけっぽい。


void FUN_00101463(undefined *param_1,undefined *param_2)

{
  undefined uVar1;
  
  uVar1 = *param_1;
  *param_1 = *param_2;
  *param_2 = uVar1;
  return;
}

ということで、すべてを繋いで、sub_check() の結果を出力すればいい。

solve.c
...

int check(char *inp){
...
        byte *res = sub_check();
        printf("%s\n",res); // 追加
...
}

int main(){
    check("AAAAAAAAAAAAAAAAAAAAAAAAAA"); // "A" * 0x1a
}

solver

ここまでをまとめてコードを書く。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define byte unsigned char

byte dat[] = {0xa5, 0xd2, 0xbc, 0x02, 0xb2, 0x7c, 0x86, 0x38, 0x17, 0xb1, 0x38, 0xc6, 0xe4, 0x5c, 0x1f, 0xa0, 0x9d, 0x96, 0xd1, 0xf0, 0x4b, 0xa6, 0xa6, 0x5c, 0x64, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte key[] = {0x43, 0x55, 0x44, 0x17, 0x46, 0x1f, 0x14, 0x17, 0x1a, 0x1d, 0x00};

void swap(byte *a,byte *b){
    byte tmp = *a;
    *a = *b;
    *b = tmp;
}

byte * sub_check(){
    byte buf[264];
    long local_10;

    int dat_len = strlen(dat);
    byte *res = malloc(dat_len);

    int key_len = strlen(key);
    for(int i = 0; i < 0x100; i++) {
        buf[i] = i;
    }
    byte t = 0;
    for(int i = 0; i < 0x100; i++) {
        t = (key[i % key_len] + buf[i] + t) & 0xff;
        swap(&buf[i],&buf[t]);
    }
    byte x = 0,y = 0;
    for(int i = 0; i < dat_len; i++) {
        x = (x + 1) & 0xff;
        y = (y + buf[x]) & 0xff;
        swap(&buf[x],&buf[y]);
        res[i] = buf[(buf[y] + buf[x]) & 0xff] ^ dat[i];
    }

    return res;
}


int check(char *inp){
    int inp_len = strlen(inp);
    if(inp_len == 0x1a) {
        for(byte i = 0;i < strlen(key); i++) {
            key[i] = (i + 0x20U) ^ key[i];
        }
        byte *res = sub_check();
        printf("%s\n",res);
        for(int i = 0; (inp[i] != '\0' && (res[i] != '\0')); i++) {
            if(inp[i] != res[i]) {
                return 0;
            }
        }
        return 1;
    }
    else {
        return 0;
    }
}

int main(){
    check("AAAAAAAAAAAAAAAAAAAAAAAAAA"); // "A" * 0x1a
}

flag: ctf4b{p7r4c3_c4n_3mul4t3_sysc4ll}

おわりに

Reversing 問題、「頑張る」以外に解説できることが本当にない…

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?