블로그 이전했습니다. https://jeongzero.oopy.io/
[HackCTF] keygen
본문 바로가기
워게임/HackCTF

[HackCTF] keygen

728x90

1. 문제


1) mitigation 확인

뭐 미티게이션을 보는건 큰 의미는 없지만.. 일단 PIE가 없다

2) 문제 확인

키를 입력받는다. 자세한건 아이다로 봐보자.

3) 코드흐름 파악

int __cdecl main(int argc, const char **argv, const char **envp)
{
  FILE *stream; // [rsp+8h] [rbp-C8h]
  char input; // [rsp+10h] [rbp-C0h]
  char v6; // [rsp+60h] [rbp-70h]
  unsigned __int64 v7; // [rsp+C8h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 2, 0LL);
  puts(s);
  fgets(&input, 0x41, stdin);
  if ( check_key(&input) )
  {
    stream = fopen("flag", "r");
    if ( !stream )
    {
      puts(&byte_400AC0);
      return 0;
    }
    fgets(&v6, 100, stream);
    printf("%s", &v6);
  }
  return 0;
}

메인에서 input에 입력을 받는다. 그리고 check_key()를 호출해서 반환값이 널이 아니면 플래그를 출력해준다.

bool __fastcall check_key(const char *input)
{
  char *input_encode; // ST10_8

  if ( strlen(input) <= 9 || strlen(input) > 0x40 )
    return 0;
  input_encode = encoding(input);
  return strcmp("OO]oUU2U<sU2UsUsK", input_encode) == 0;
}

일단 입력값은 사이즈가 9보단 커야하고 0x40보단 작아야한다. 그다음 encode()함수를 호출해서 반환값이랑 어떤 괴상한 문자열이랑 비교한다.

_BYTE *__fastcall encoding(const char *input)
{
  unsigned __int8 v2; // [rsp+1Fh] [rbp-11h]
  int i; // [rsp+20h] [rbp-10h]
  int len; // [rsp+24h] [rbp-Ch]
  _BYTE *buf; // [rsp+28h] [rbp-8h]

  buf = malloc(0x40uLL);
  len = strlen(input);
  v2 = 0x48;
  for ( i = 0; i < len; ++i )
  {
    buf[i] = ((input[i] + 12) * v2 + 17) % 70 + 48;
    v2 = buf[i];
  }
  return buf;
}

요게 실제 인코딩 로직이다. 입력값이 위 로직을 거쳐서 아까 괴상한 문자열이 되게끔하면 된다.

2. 접근방법


첨에는 저 로직을 수학적으로 역연산 그지랄 할라고했는데 생각해보니 그럴필요가 없었음. 어짜피 내가 입력할수 있는 값은 아스키값 범위가 정해져 있고, 그냥 저 encode 로직을 구현한뒤, 32~126까지 브포 떄려서 괴상한 문자열의 문자 하나씩 비교하면 끝임

key='OO]oUU2U<sU2UsUsK'


def encode(key):
        v2=0x48;
        buf=''
        index=0
        for j in range(len(key)):
                for i in range(32,127):
                        tmp=((i+12)*v2+17)%70+48
                        if ord(key[j]) == tmp:
                                print('tmp: ',chr(tmp)),
                                print('key: ',key[j])
                                buf+=chr(i)
                                v2=tmp
                                break
        print(buf)

간단히 구현할수 있다.

3. 풀이


코드를 돌리면

╰─$ python ex.py 
('tmp: ', 'O') ('key: ', 'O')
('tmp: ', 'O') ('key: ', 'O')
('tmp: ', ']') ('key: ', ']')
('tmp: ', 'o') ('key: ', 'o')
('tmp: ', 'U') ('key: ', 'U')
('tmp: ', 'U') ('key: ', 'U')
('tmp: ', '2') ('key: ', '2')
('tmp: ', 'U') ('key: ', 'U')
('tmp: ', '<') ('key: ', '<')
('tmp: ', 's') ('key: ', 's')
('tmp: ', 'U') ('key: ', 'U')
('tmp: ', '2') ('key: ', '2')
('tmp: ', 'U') ('key: ', 'U')
('tmp: ', 's') ('key: ', 's')
('tmp: ', 'U') ('key: ', 'U')
('tmp: ', 's') ('key: ', 's')
('tmp: ', 'K') ('key: ', 'K')
A,d<&$+$'  +$& &&

저렇게 나오는데 답이 틀렸다고 함. 웨지? 디버깅 ㄱ

'A,d<&$+$' +$& &&' 요거 그대로 넣고 strcmp 보면

끝에 문자 하나가 더 들어가있다. 아마 마지막 개행 문자까지 인코딩된듯 저거 빼주고 하면 된다.

4. 몰랐던 개념


리버싱 문제는 왜케 적응이 안ㄷ...

728x90

'워게임 > HackCTF' 카테고리의 다른 글

[HackCTF] BabyMips  (0) 2020.12.04
[HackCTF] static  (0) 2020.12.03
[HackCTF] strncmp  (0) 2020.12.01
[HackCTF] adultfsb  (1) 2020.04.12
[HackCTF] 훈폰정음  (0) 2020.04.12