2019 제 17회 순천향대학교 정보보호 페스티벌(YISF) 예선 풀이
Web 50
편지를 쓰다 말고 훈련소에 끌려 갔다고 해서 .swp 파일인 것을 짐작 할 수 있었다.
http://218.158.141.133/.index.php.swp이 링크로 들어가면 서버 사이드 스크립트가 노출된다.
Magic hash 문제다.
입력한 한 문자열 + “S@L7”을 md5 encrypt 한 값과 0e123142351이 같으면 된다.
그러므로 입력한 문자열 + “S@L7” 의 md5 hash 값은 0e + 숫자 30바이트이면 된다.
import hashlib | |
import re | |
import string | |
ALLOWED_CHARACTERS = string.hexdigits | |
NUMBER_OF_CHARACTERS = len(ALLOWED_CHARACTERS) | |
def characterToIndex(char): | |
return ALLOWED_CHARACTERS.index(char) | |
def indexToCharacter(index): | |
if NUMBER_OF_CHARACTERS <= index: | |
raise ValueError("Index out of range.") | |
else: | |
return ALLOWED_CHARACTERS[index] | |
def next(string): | |
if len(string) <= 0: | |
string.append(indexToCharacter(0)) | |
else: | |
string[0] = indexToCharacter((characterToIndex(string[0]) + 1) % NUMBER_OF_CHARACTERS) | |
if characterToIndex(string[0]) is 0: | |
return list(string[0]) + next(string[1:]) | |
return string | |
def main(): | |
sequence = list() | |
while True: | |
sequence = next(sequence) | |
tmp = ''.join(i for i in sequence) | |
tmp += 'S@L7' | |
m = hashlib.md5() | |
m.update(tmp) | |
md5string=m.hexdigest() | |
if md5string[2:].isdigit() == True and md5string[:2] == '0e': | |
print md5string + " : " + tmp | |
if __name__ == "__main__": | |
main() |
이렇게 문자열Brute Force Attack 해서 입력한 값의 hash 값이 0e + 숫자가 나올 때까지 돌렸다.
한 2분정도 지나니까 403a8b가 나왔다. 이거 넣어주면 된다.
FLAG : YISF{Ma9ic_L3t7er_fr0m_Pr1v4te}
Reversing 50
현재 경로 가져와서 경로를 저장한다. 프로그램의 경로를 strncmp 분기 다 맞춰주면 된다.
그러면 /aaaaaYISF/TOP_SECRET/TOP_SEflag
이런 경로까지 가면 id, password를 입력할 수 있는 창이 나오게된다.
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char *v3; // ST20_8
signed __int64 v4; // rdi
char *v6; // [rsp+18h] [rbp-A8h]
char buf; // [rsp+30h] [rbp-90h]
unsigned __int64 v8; // [rsp+B8h] [rbp-8h]
v8 = __readfsqword(0x28u);
memset(&buf, 0, 0x80uLL);
v6 = strrchr(*a2, 47) + 1;
v3 = getcwd(&buf, 0x80uLL);
printf("path : %s\nfilename : %s\n\n", v3, v6, a2);
sub_B2F(v3, v6);
if ( dword_20240C == 1 )
{
v4 = (signed __int64)(v6 + 6);
if ( !strncmp(v6 + 6, "flag", 4uLL) )
{
++dword_20240C;
sub_DE7(v4, "flag");
}
sub_D64(v4, "flag");
}
return 0LL;
}
id는The_World_Best_Programmer
인지 비교하고 password는 qwe123
이면 success!!가 뜬다. 그리고 어떠한 변수 값이 증가하면서 어떤 if문에 들어가서v6+6의 값이 flag인지 비교한다.
이건 동적디버깅해서 위치 어디인지 가져와서 그 위치에 맞게 파일 이름을 변경했다. 또 어떤 변수 값 하나를 증가시켜서 함수에서 플래그를 생성해준다.
char *__fastcall sub_B2F(__int64 a1, __int64 a2)
{
char *dest; // [rsp+18h] [rbp-98h]
char s[8]; // [rsp+20h] [rbp-90h]
__int64 v5; // [rsp+28h] [rbp-88h]
__int64 v6; // [rsp+30h] [rbp-80h]
__int64 v7; // [rsp+38h] [rbp-78h]
__int64 v8; // [rsp+40h] [rbp-70h]
__int64 v9; // [rsp+48h] [rbp-68h]
__int64 v10; // [rsp+50h] [rbp-60h]
__int64 v11; // [rsp+58h] [rbp-58h]
char v12[8]; // [rsp+60h] [rbp-50h]
__int64 v13; // [rsp+68h] [rbp-48h]
__int64 v14; // [rsp+70h] [rbp-40h]
__int64 v15; // [rsp+78h] [rbp-38h]
__int64 v16; // [rsp+80h] [rbp-30h]
__int64 v17; // [rsp+88h] [rbp-28h]
__int64 v18; // [rsp+90h] [rbp-20h]
__int64 v19; // [rsp+98h] [rbp-18h]
unsigned __int64 v20; // [rsp+A8h] [rbp-8h]
v20 = __readfsqword(0x28u);
*s = 0LL;
v5 = 0LL;
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0LL;
v10 = 0LL;
v11 = 0LL;
*v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
v15 = 0LL;
v16 = 0LL;
v17 = 0LL;
v18 = 0LL;
v19 = 0LL;
dest = malloc(0x40uLL);
if ( !strncmp((a1 + 6), "YISF", 4uLL) )
{
puts("\nHmm...?\n");
if ( !strncmp((a1 + 11), "TOP_SECRET", 0xAuLL) )
{
puts("Please enter your ID and Password...\n");
printf("ID : ", "TOP_SECRET", a2);
fgets(s, 64, stdin);
printf("PW : ", 64LL);
fgets(v12, 64, stdin);
strcpy(dest, v12);
if ( strncmp(s, aTheWorldBestPr, 0x19uLL) || strncmp(v12, aQwe123, 6uLL) )
{
puts("\nYou don't have permission!!\n");
exit(0);
}
puts("\nsuccess!!\n");
++dword_20240C;
}
else
{
puts("Invalid Directory Name\n");
}
}
else
{
puts("Ivalid Directory Name\n");
}
return dest;
}
FLAG : YISF{5252~~_I_6eliev3d!!!}
Reversing 100
어차피 마지막에 플래그 출력해줄 것 같았다.
FLAG 출력해줄 인코딩된 테이블을 가져와서 XOR Brute Force Attack 했더니 플래그가 나왔다.
a=[0xc8,0xd8,0xc2,0xd7,0xea,0xa5,0xe3,0xf4,0xce,0xc8,0xa1,0xe4,0xce,0xf0,0xce,0xd2,0xf9,0xa2,0xf0,0xa6,0xf4,0xe3,0xae,0xae,0xec]
print ''.join(chr(i^145) for i in a)
FLAG : YISF{4re_Y0u_a_Ch3a7er??}
Misc 50
Introduce 들어가서 보면 된다.
확인을 누르면 alert 띄워서FLAG 준다.
FLAG : YISF{G00D_LUCK_3V3RY01V3}
Misc 100
주어진 nc로 들어가게되면 아래처럼 직선방정식으로 삼각형 넓이를 구하라고 x,y 값을 준다.
x,y값을 구한후 일명 신발끈 공식을 이용해 삼각형의 넓이를 구했다.
참고 : 신발끈 공식
from z3 import * | |
from pwn import * | |
p = remote('218.158.141.199',24763) | |
s = Solver() | |
x = [Int('x%i'%i)for i in range(12,130)] | |
y = [Int('y%i'%i)for i in range(12,130)] | |
x1 = [Int('x1%i'%i)for i in range(12,130)] | |
y1 = [Int('y1%i'%i)for i in range(12,130)] | |
x2 = [Int('x2%i'%i)for i in range(12,130)] | |
y2 = [Int('y2%i'%i)for i in range(12,130)] | |
p.recvuntil('<Quiz Start>\n') | |
for i in range(100): | |
print "[*]"+str(i) | |
li = [] | |
print p.recvuntil('Step : ' + str(i+1) + "\n\n") | |
a = p.recvline() | |
print a | |
tmp1 = a.split(' ') | |
b = p.recvline() | |
print b | |
tmp2 = b.split(' ') | |
c = p.recvline() | |
print c | |
tmp3 = c.split(' ') | |
s.add(int(tmp1[0]) * x[12+i] + int(tmp1[3]) * y[12+i] == int(tmp1[6].replace("\n",""))) | |
s.add(int(tmp2[0]) * x[12+i] + int(tmp2[3]) * y[12+i] == int(tmp2[6].replace("\n",""))) | |
s.check() | |
m = s.model() | |
li.append(int(str(m.evaluate(x[i+12])))) | |
li.append(int(str(m.evaluate(y[i+12])))) | |
s.add(int(tmp1[0]) * x1[12+i] + int(tmp1[3]) * y1[12+i] == int(tmp1[6].replace("\n",""))) | |
s.add(int(tmp3[0]) * x1[12+i] + int(tmp3[3]) * y1[12+i] == int(tmp3[6].replace("\n",""))) | |
s.check() | |
m = s.model() | |
li.append(int(str(m.evaluate(x1[i+12])))) | |
li.append(int(str(m.evaluate(y1[i+12])))) | |
s.add(int(tmp2[0]) * x2[12+i] + int(tmp2[3]) * y2[12+i] == int(tmp2[6].replace("\n",""))) | |
s.add(int(tmp3[0]) * x2[12+i] + int(tmp3[3]) * y2[12+i] == int(tmp3[6].replace("\n",""))) | |
s.check() | |
m = s.model() | |
li.append(int(str(m.evaluate(x2[i+12])))) | |
li.append(int(str(m.evaluate(y2[i+12])))) | |
print li | |
payload=(abs((li[0]*li[3]+li[2]*li[5]+li[4]*li[1]) - (li[2]*li[1]+li[4]*li[3]+li[0]*li[5])))*0.5 | |
print payload | |
p.sendlineafter('Input :',str(payload)) | |
p.interactive() |
좀 코드가 더럽긴한데.. 자꾸 11번째에서 오류나길래 인덱스 12부터 시작해줬더니 오류가 안나고 풀렸다.
FLAG : YISF{Mathematical_ability_i5_n0t_ru5ty}
Misc 150
주어진 nc 서버를 들어가면 딕셔너리를 주어서 만들 수 있는 경우를 브루트포스해서 문자를 만들어서 보내면 된다.
근데 딕셔너리가 문자로 주어져서 ast 모듈을 사용해서 풀었다.
from pwn import * | |
from ast import literal_eval | |
p = remote('218.158.141.182',52387) | |
for i in range(100): | |
payload="" | |
print p.recvuntil('Step : ' + str(i+1) + "\n\n") | |
text = p.recvline() | |
text = list(text) | |
del(text[-1]) | |
heigth = p.recvline() | |
table = p.recvline() | |
table = table[9:] | |
dictionary = literal_eval(table) | |
value = list(dictionary.keys()) | |
while len(text) != 0: | |
for i in range(1,5): | |
tmp = text[:i] | |
tmp2 = ''.join(i for i in tmp) | |
for j in range(5): | |
if tmp2 == dictionary[value[j]]: | |
payload += value[j] | |
del text[:i] | |
print payload | |
p.sendline(payload) | |
p.interactive() |
FLAG : YISF{Y0u_make_table_WeLL}