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}