[CTF Writeup / Reversing] IrisCTF 2024 - The Johnson's
The Johnson's
Please socialize with the Johnson's and get off your phone. You might be quizzed on it!
제공된 바이너리를 실행시키면 다음과 같다.
질문에 대한 응답값은 분석을 통해 알아냈다. 순서가 맞지 않으면 위와 같이 incorrect를 출력한다.
ghidra로 열어보면 main 함수가 다음과 같이 구성되어있다.
undefined8 main(void)
{
int iVar1;
long in_FS_OFFSET;
int local_84;
int local_80;
int local_7c;
char local_78 [104];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
puts("Welcome to the Johnson\'s family!");
puts(
"You have gotten to know each person decently well, so let\'s see if you remember all of the f acts."
);
puts("(Remember that each of the members like different things from each other.)");
local_84 = 0;
while (local_84 < 4) {
printf("Please choose %s\'s favorite color: ",*(undefined8 *)(names + (long)local_84 * 8));
__isoc99_scanf(&DAT_0010217c,local_78);
iVar1 = strcmp(local_78,colors);
if (iVar1 == 0) {
local_80 = 1;
LAB_00101449:
if ((((local_80 == chosenColors[0]) || (local_80 == chosenColors[1])) ||
(local_80 == chosenColors[2])) || (local_80 == chosenColors[3])) {
puts("That option was already chosen!");
}
else {
chosenColors[local_84] = local_80;
local_84 = local_84 + 1;
}
}
else {
iVar1 = strcmp(local_78,PTR_s_blue_00104048);
if (iVar1 == 0) {
local_80 = 2;
goto LAB_00101449;
}
iVar1 = strcmp(local_78,PTR_s_green_00104050);
if (iVar1 == 0) {
local_80 = 3;
goto LAB_00101449;
}
iVar1 = strcmp(local_78,PTR_s_yellow_00104058);
if (iVar1 == 0) {
local_80 = 4;
goto LAB_00101449;
}
puts("Invalid color!");
}
}
local_84 = 0;
do {
while( true ) {
if (3 < local_84) {
check();
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
printf("Please choose %s\'s favorite food: ",*(undefined8 *)(names + (long)local_84 * 8));
__isoc99_scanf(&DAT_0010217c,local_78);
iVar1 = strcmp(local_78,foods);
if (iVar1 != 0) break;
local_7c = 1;
LAB_0010159c:
if (((local_7c == chosenFoods_val4[0]) || (local_7c == chosenFoods_val4[1])) ||
((local_7c == chosenFoods_val4[2] || (local_7c == chosenFoods_val4[3])))) {
puts("That option was already chosen!");
}
else {
chosenFoods_val4[local_84] = local_7c;
local_84 = local_84 + 1;
}
}
iVar1 = strcmp(local_78,PTR_s_pasta_00104068);
if (iVar1 == 0) {
local_7c = 2;
goto LAB_0010159c;
}
iVar1 = strcmp(local_78,PTR_s_steak_00104070);
if (iVar1 == 0) {
local_7c = 3;
goto LAB_0010159c;
}
iVar1 = strcmp(local_78,PTR_s_chicken_00104078);
if (iVar1 == 0) {
local_7c = 4;
goto LAB_0010159c;
}
puts("Invalid food!");
} while( true );
}
추가로 살펴볼 부분은 check 함수다. 다음과 같다.
void check(void)
{
byte bVar1;
bool bVar2;
if ((chosenFoods_val4[2] == 2) || (chosenFoods_val4[3] == 2)) {
bVar2 = false;
}
else {
bVar2 = true;
}
if ((chosenColors[0] == 3) || (chosenColors[1] == 3)) {
bVar1 = 0;
}
else {
bVar1 = 1;
}
if (chosenColors[3] == 2 &&
(chosenColors[2] != 4 &&
(chosenFoods_val4[3] != 3 &&
(chosenFoods_val4[0] == 4 && (bool)((chosenColors[1] != 1 && bVar2) & bVar1))))) {
puts("Correct!");
system("cat flag.txt");
}
else {
puts("Incorrect.");
}
return;
}
결국에 check 함수를 실행했을 때, 모든 조건이 맞아야 cat flag.txt 명령을 통해 플래그를 획득할 수 있다.
로직은 간단한데, user 4명이 있고, 각자의 color와 food를 맞추면 된다. 랜덤도 아니고 고정이라 브포도 가능해서 어렵지 않다.
바이너리를 분석해서 데이터를 python 코드로 살짝 옮겨보면 다음과 같다.
color_ele ={
'red': 1,
'blue': 2,
'green': 3,
'yellow': 4
}
food_ele = {
'pizza': 1,
'pasta': 2,
'steak': 3,
'chicken': 4
}
이번에는 각자의 color와 food가 뭔지 분석해봤다.
check 함수 내 조건문을 통해 알아낼 수 있다.
colors = [get_ele_from_num(color_ele, n) for n in [1, 4, 3, 2]]
foods = [get_ele_from_num(food_ele, n) for n in [4, 2, 3, 1]]
print(colors, foods)
로컬에서 위 데이터를 기반으로 성공했다. remote로 변경해서 시도해서 flag를 얻을 수 있었다.
# x = process('./main')
x = remote('babyrevjohnson.chal.irisc.tf', 10002)
x.recvuntil(b'Remember')
for color in colors:
x.sendline(color.encode())
for food in foods:
x.sendline(food.encode())
x.interactive()
irisctf{m0r3_th4n_0n3_l0g1c_puzzl3_h3r3}
댓글
댓글 쓰기