<문제>
Yay reversing! Relevant files: otp flag.txt
otp 파일을 ghidra로 까서 본 main 함수
undefined8 main(int param_1,undefined8 *param_2)
{
char cVar1;
byte bVar2;
int iVar3;
undefined8 uVar4;
long in_FS_OFFSET;
int local_f0;
int local_ec;
char local_e8 [100];
undefined local_84;
char local_78 [104];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
if (param_1 < 2) {
printf("USAGE: %s [KEY]\n",*param_2);
uVar4 = 1;
}
else {
strncpy(local_e8,(char *)param_2[1],100);
local_84 = 0;
local_f0 = 0;
while( true ) {
iVar3 = valid_char((ulong)(uint)(int)local_e8[local_f0]);
if (iVar3 == 0) break;
if (local_f0 == 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[local_f0 + -1] >> 0x37);
local_78[local_f0] =
((char)((int)cVar1 + (int)local_78[local_f0 + -1]) + (bVar2 >> 4) & 0xf) - (bVar2 >>4)
;
}
local_f0 = local_f0 + 1;
}
local_ec = 0;
while (local_ec < local_f0) {
local_78[local_ec] = local_78[local_ec] + 'a';
local_ec = local_ec + 1;
}
if (local_f0 == 100) {
iVar3 = strncmp(local_78,
"mngjlepdcbcmjmmjipmmegfkjbicaemoemkkpjgnhgomlknmoepmfbcoffikhplmadmganmlojndmfahbhaancamdhfdkiancdjf"
,100);
if (iVar3 == 0) {
puts("You got the key, congrats! Now xor it with the flag!");
uVar4 = 0;
goto LAB_001009ea;
}
}
puts("Invalid key!");
uVar4 = 1;
}
LAB_001009ea:
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return uVar4;
}
valid_char 함수
undefined8 valid_char(char param_1)
{
undefined8 uVar1;
if ((param_1 < '0') || ('9' < param_1)) {
if ((param_1 < 'a') || ('f' < param_1)) {
uVar1 = 0;
}
else {
uVar1 = 1;
}
}
else {
uVar1 = 1;
}
return uVar1;
}
jumble 함수
ulong jumble(char param_1)
{
byte bVar1;
byte local_c;
local_c = param_1;
if ('`' < param_1) {
local_c = param_1 + '\t';
}
bVar1 = (byte)((char)local_c >> 7) >> 4;
local_c = ((local_c + bVar1 & 0xf) - bVar1) * '\x02';
if ('\x0f' < (char)local_c) {
local_c = local_c + 1;
}
return (ulong)local_c;
}
모든 함수를 자세히 해석할 순 없었고 순서를 정리해보면 파라미터를 2개 받아와,
1) 두번째 파라미터를 길이 100만큼 복사한다
2) valid_char 함수에서는 문자를 0과 9, a와 f 사이로 정의하는 걸 보니 16진수로 나타낸다
3) jumble 함수는 char값을 받아와 처리하는 함수 정도로 밖에 모르겠다
gdb로 열어 strncmp에 break를 걸고 레지스터 값을 봤을 때, 길이 100의 문자열을 입력했을 때 acgme... 처럼 문자열이 처리되어 저장된 것을 볼 수 있었다

이건 문자열 변환 과정같다.

앞문자를 바꿔보며 돌려 rdi 레지스터 값을 보면 여기서 6일때, m이라는 문자가 나오는 것을 볼수 있다. 근데 한 자리가 바뀔 때마다 뒷자리 문자도 바뀌는 것을 보니 아마 각 자리의 문자 변환할 때 서로 영향을 미치는 것을 알 수 있다. 그래도 이 문제는 0~9사이, a~f사이의 문자 하나하나 비교해가며 brute force를 통해 풀 수 있을 것 같다.

<문제 풀이 코드>
from pwn import *
p=process(["gdb", "./otp"])
p.recvuntil("(gdb)")
p.sendline("b strncmp@plt")
p.recvuntil("(gdb)")
chars="0123456789abcdef"
sofar=""
for j in range(100):
for i in chars:
p.sendline("run "+sofar+"1"*(99-j)
p.recvuntil("(gdb)")
p.sendline("x/s $rsi")
first=(p.recvuntil("(gdb)"))
p.sendline("x/s $rdi")
second=(p.recvuntil("(gdb)"))
if first[18+j]==second[18+j]:
sofar += i
print(sofar)
break
이 코드를 이용한 brute force 공격으로 local_78에 들어가야할 key 값을 구하고,

그 결과 값을 flag와 XOR 한 다음

결과값을 16진수->ASCII 복호화 해보면

FLAG : picoCTF{cust0m_jumbl3s_4r3nt_4_g0Od_1d3A_33ead16f}
'CTF > Reversing' 카테고리의 다른 글
[picoCTF] droids1 (0) | 2021.01.20 |
---|---|
[picoCTF] droids0 (0) | 2021.01.12 |
[picoCTF] asm2 (0) | 2021.01.10 |
[picoCTF] vault-door 4 (0) | 2021.01.10 |
[Hitcon2020] Welcome (0) | 2020.11.30 |
<문제>
Yay reversing! Relevant files: otp flag.txt
otp 파일을 ghidra로 까서 본 main 함수
undefined8 main(int param_1,undefined8 *param_2)
{
char cVar1;
byte bVar2;
int iVar3;
undefined8 uVar4;
long in_FS_OFFSET;
int local_f0;
int local_ec;
char local_e8 [100];
undefined local_84;
char local_78 [104];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
if (param_1 < 2) {
printf("USAGE: %s [KEY]\n",*param_2);
uVar4 = 1;
}
else {
strncpy(local_e8,(char *)param_2[1],100);
local_84 = 0;
local_f0 = 0;
while( true ) {
iVar3 = valid_char((ulong)(uint)(int)local_e8[local_f0]);
if (iVar3 == 0) break;
if (local_f0 == 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[local_f0 + -1] >> 0x37);
local_78[local_f0] =
((char)((int)cVar1 + (int)local_78[local_f0 + -1]) + (bVar2 >> 4) & 0xf) - (bVar2 >>4)
;
}
local_f0 = local_f0 + 1;
}
local_ec = 0;
while (local_ec < local_f0) {
local_78[local_ec] = local_78[local_ec] + 'a';
local_ec = local_ec + 1;
}
if (local_f0 == 100) {
iVar3 = strncmp(local_78,
"mngjlepdcbcmjmmjipmmegfkjbicaemoemkkpjgnhgomlknmoepmfbcoffikhplmadmganmlojndmfahbhaancamdhfdkiancdjf"
,100);
if (iVar3 == 0) {
puts("You got the key, congrats! Now xor it with the flag!");
uVar4 = 0;
goto LAB_001009ea;
}
}
puts("Invalid key!");
uVar4 = 1;
}
LAB_001009ea:
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return uVar4;
}
valid_char 함수
undefined8 valid_char(char param_1)
{
undefined8 uVar1;
if ((param_1 < '0') || ('9' < param_1)) {
if ((param_1 < 'a') || ('f' < param_1)) {
uVar1 = 0;
}
else {
uVar1 = 1;
}
}
else {
uVar1 = 1;
}
return uVar1;
}
jumble 함수
ulong jumble(char param_1)
{
byte bVar1;
byte local_c;
local_c = param_1;
if ('`' < param_1) {
local_c = param_1 + '\t';
}
bVar1 = (byte)((char)local_c >> 7) >> 4;
local_c = ((local_c + bVar1 & 0xf) - bVar1) * '\x02';
if ('\x0f' < (char)local_c) {
local_c = local_c + 1;
}
return (ulong)local_c;
}
모든 함수를 자세히 해석할 순 없었고 순서를 정리해보면 파라미터를 2개 받아와,
1) 두번째 파라미터를 길이 100만큼 복사한다
2) valid_char 함수에서는 문자를 0과 9, a와 f 사이로 정의하는 걸 보니 16진수로 나타낸다
3) jumble 함수는 char값을 받아와 처리하는 함수 정도로 밖에 모르겠다
gdb로 열어 strncmp에 break를 걸고 레지스터 값을 봤을 때, 길이 100의 문자열을 입력했을 때 acgme... 처럼 문자열이 처리되어 저장된 것을 볼 수 있었다

이건 문자열 변환 과정같다.

앞문자를 바꿔보며 돌려 rdi 레지스터 값을 보면 여기서 6일때, m이라는 문자가 나오는 것을 볼수 있다. 근데 한 자리가 바뀔 때마다 뒷자리 문자도 바뀌는 것을 보니 아마 각 자리의 문자 변환할 때 서로 영향을 미치는 것을 알 수 있다. 그래도 이 문제는 0~9사이, a~f사이의 문자 하나하나 비교해가며 brute force를 통해 풀 수 있을 것 같다.

<문제 풀이 코드>
from pwn import *
p=process(["gdb", "./otp"])
p.recvuntil("(gdb)")
p.sendline("b strncmp@plt")
p.recvuntil("(gdb)")
chars="0123456789abcdef"
sofar=""
for j in range(100):
for i in chars:
p.sendline("run "+sofar+"1"*(99-j)
p.recvuntil("(gdb)")
p.sendline("x/s $rsi")
first=(p.recvuntil("(gdb)"))
p.sendline("x/s $rdi")
second=(p.recvuntil("(gdb)"))
if first[18+j]==second[18+j]:
sofar += i
print(sofar)
break
이 코드를 이용한 brute force 공격으로 local_78에 들어가야할 key 값을 구하고,

그 결과 값을 flag와 XOR 한 다음

결과값을 16진수->ASCII 복호화 해보면

FLAG : picoCTF{cust0m_jumbl3s_4r3nt_4_g0Od_1d3A_33ead16f}
'CTF > Reversing' 카테고리의 다른 글
[picoCTF] droids1 (0) | 2021.01.20 |
---|---|
[picoCTF] droids0 (0) | 2021.01.12 |
[picoCTF] asm2 (0) | 2021.01.10 |
[picoCTF] vault-door 4 (0) | 2021.01.10 |
[Hitcon2020] Welcome (0) | 2020.11.30 |