Description

Category: Reversing/Android

Source: TAMUctf 2019

Points: 418

Author: Jisoon Park(js00n.park)

Description:

Can you find my secrets?

howdyapp.apk

Write-up

android 문제이다. 주어진 apk 파일을 emulator에 설치해서 실행시켜 보았지만 그림을 누를때마다 카운트가 올라가는 것 외에 특별한 동작은 없었다.

jadx-gui를 사용해서 MainActivity의 코드를 살펴보았어도 별다른 것을 찾을 수 없었다.

package com.tamu.ctf.howdyapp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView((int) R.layout.activity_main);
        final TextView buttonCount = (TextView) findViewById(R.id.count);
        ((ImageButton) findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                buttonCount.setText(String.valueOf(Integer.valueOf(buttonCount.getText().toString()).intValue() + 1));
            }
        });
    }
}

특별히 문자열을 변환해서 보여주는 구문 같은 것도 없으니, 어찌됐건 뭐가됐건 apk 내에 flag 문자열이 있을 거라고 생각하고 gigem이나 flag 문자열을 찾아봤더니 classes.dex와 resources.arsc 파일 내에 그런 문자열이 있었다.

코드를 뒤져봤을 때는 별게 없었으니까 resources.arsc를 열심히 찾아보자.

resources.arsc/res/values/strings.xml 파일에서 다음과 같은 값들을 찾을 수 있었다.

flag라고 써있는 문자열을 base64 디코딩 했더니 flag를 얻을 수 있다.

Flag : gigem{infinite_gigems}

'writeups > Reversing' 카테고리의 다른 글

Feed_me  (0) 2019.11.25
Snakes over cheese  (0) 2019.11.25
Local News  (0) 2019.11.25
KeyGenMe  (0) 2019.11.25
rock  (0) 2019.11.25

Description

Category: Web

Source: TAMUctf 2019

Author: Jisoon Park(js00n.park)

  • 0_Network_Enumeration

Points: 100

Description:

Recently, the office put up a private webserver to store important information about the newest research project for the company. This information was to be kept confidential, as it's release could mean a large loss for everyone in the office.

Just as the research was about to be published, a competing firm published information eerily similar. Too similar...

Time to take a look through the office network logs to figure out what happened.

  1. What is the IP address of the private webserver?
  2. How many hosts made contact with the private webserver that day?

Difficulty: easy

capture.pcap

Write-up

PCAP 파일이 주어졌다. wireshark로 열어보자.

webserver라고 했으니 80번 포트로의 연결을 받아들이는 IP를 찾아보자.

거의 맨 위에 192.168.11.4가 나오는걸 알 수 있다. 넣어보니 맞다고 한다.

ip.dst == 192.168.11.4 필터를 적용한 후 Source IP를 세어보면 총 13개의 IP 주소를 확인할 수 있다.

1 : 192.168.11.4
2 : 13

  • 1_Discovery

Points: 100

Description:

  1. What is the IP address of the host exfiltrating data?
  2. For how long did the exfiltration happen? (Round to the nearest second. Format: MM:SS)
  3. What protocol/s was used to exfiltrate data? (Alphabetical order, all caps, comma separated, with spaces - ex: ABCD, BBCD)

Difficulty: easy

Write-up

위에서 webserver에 접속하는 IP가 13개였었다. 순서대로 하나씩 넣어보면 192.168.11.7임을 알 수 있었다.

192.168.11.4와 192.168.11.7간의 통신 패킷들을 보면, 첫 패킷의 timestamp가 14:24:40이고, 마지막 패킷의 timestamp가 14:35:49이다. 두 시간을 빼보면 11분 9초임을 알 수 있다.

통신 프로토콜은 ICMP, TCP, HTTP, DNS의 네 가지를 이용하는데, 하나씩 살펴보면 SYN/ACK에만 사용되는 TCP 패킷을 제외하고 나머지 패킷들은 뭔가 데이터들을 들고 다니는 것을 확인할 수 있다.

1 : 192.168.11.7
2 : 11:09
3 : DNS, ICMP, HTTP

  • 2_Exfiltration

Points: 100

Description:

  1. What is the name of the stolen file?
  2. What is the md5sum of the stolen file?

Difficulty: easy

Write-up

192.168.11.4와 192.168.11.7 간에 교환되는 패킷을 살펴보면, 맨 처음에 ICMP 패킷이 보인다.

Ping Request/Reply인데, 일반적인 Ping과는 다르게 Payload가 있다.

이 값들을 decoding 해보자. 중간에 e라는 문자가 들어있는 걸로 봐서는 hex 데이터인것 같다.

디코딩 했더니 뭔가 읽을 수 있는 문자열이 나왔다. 딱 봐도 .(dot)은 field 구분자인 것 같다.

구분된 각각의 필드를 파일 이름으로 submit 해보았지만 아니었다. 중간에 있는 746f로 시작하는 데이터를 한번 더 디코딩 해보았더니 파일 이름같이 생긴 것이 나와서 넣어봤더니 정답이었다.

그렇다면 마지막에 있는 데이터는 16 바이트 길이인 것이 md5sum인 것 같다. submit 해보니 맞았다.

1 : totally_nothing.pdf
2 : 6156eab6691f32b8350c45b3fc4aadc1

3_Data

Points: 100

Description:

  1. What compression encoding was used for the data?
  2. What is the name and type of the decompressed file? (Format: NAME.TYPE e.g. tamuctf.txt)

Difficulty: medium-hard

Write-up

DNS, ICMP, HTTP 프로토콜을 이용해서 전송되는 데이터들을 살펴보면, 각자의 방법으로 공통된 유형의 데이터를 보내고 있다.

http 포로토콜은 POST payload를 이용해서 전송하고 있다.

ICMP 프로토콜은 optional field인 message payload를 이용해서 전송한다.

DNS 프로토콜은 DNS query 메세지에 데이터를 실어보낸다.

wireshark로 각 프로토콜별로 메세지를 필터링하여 JSON 형태로 export 하였다.

각각의 프로토콜로 전송되는 메세지를 hex decode 해보면 SEx4IRV.n.data 형식의 데이터를 획득할 수 있었다.

3가지 프로토콜로부터 총 51개의 데이터를 얻어내어 n으로 지정되는 순서에 따라 배치하고 hex decode를 한번 더 수행하는 코드를 작성한 결과 file의 데이터를 얻을 수 있었다.

결과 file은 gzip 형식으로 압축되어 있었고, 이를 압축 해제하여 생성된 파일은 tar 파일이었다. (.tar.gz였다는 뜻)

tar를 풀어주자 최종적으로 stuff라는 elf 파일이 생성되었다.

1 : gzip
2 : stuff.elf

'writeups > Web' 카테고리의 다른 글

Cookie Monster  (0) 2019.11.25
Stop and Listen  (0) 2019.11.25
webhacking.kr 024  (0) 2019.11.25
webhacking.kr 027  (0) 2019.11.25
webhacking.kr 054  (0) 2019.11.25

Description

Category: Reversing/Android

Source: TAMUctf 2019

Points: 478

Author: Jisoon Park(js00n.park)

Description:

Be sure to check your local news broadcast for the latest updates!

Difficulty: medium-hard

app.apk

Write-up

우선 jadx-gui를 사용해 MainActivity를 살펴보자.

public class MainActivity extends AppCompatActivity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView((int) R.layout.activity_main);
        BroadcastReceiver hidden = new BroadcastReceiver() {
            public void onReceive(Context context, Intent intent) {
                Log.d(MainActivity.this.getString(R.string.flag), Deobfuscator$app$Debug.getString(0));
            }
        };
        IntentFilter filter = new IntentFilter();
        filter.addAction(getString(R.string.hidden_action));
        LocalBroadcastManager.getInstance(this).registerReceiver(hidden, filter);
    }
}

BroadcastReceiver를 만들어서 OnReceive() 함수를 정의하는데, 뭔가 broadcast가 들어오면 Deobfuscator 클래스의 getString(0) 메소를 호출해서 그 결과를 로그로 출력하고 있다. 해당 클래스를 따라가보자.

Deobfuscator 클래스에는 getString() 메소드 하나 밖에 없다. 일단 에뮬레이터에 앱을 올린 후 브로드캐스트를 날려 보는 것도 방법이겠지만, 귀찮으니 그냥 아래와 같이 코드를 복사해서 돌려보았다.

public class HelloWorld{
    private static final String[] charChunks = new String[]{"}18m_hanbed3i{0g"};
    private static final String[] indexChunks = new String[]{"\u000f\f\u000f\t\u0003\r\u0005\f\n\n\t\u0007\u0004\u0002\u0001\u0006\t\b\u000e\u0001\u000b\b\t\u0006\u0000"};
    private static final String[] locationChunks = new String[]{"\u0000\u0000\u0019\u0000"};

    public static final int USER_MASK = 65535;

    public static String getString(int id) {
        int location1Index = id % 4096;
        int location2ChunkIndex = (id + 1) / 4096;
        int location2Index = (id + 1) % 4096;
        String locations1 = locationChunks[id / 4096];
        String locations2 = locationChunks[location2ChunkIndex];
        int offset1 = ((locations1.charAt((location1Index * 2) + 1) & USER_MASK) << 16) | (locations1.charAt(location1Index * 2) & USER_MASK);
        int length = ((locations2.charAt((location2Index * 2) + 1) << 16) | locations2.charAt(location2Index * 2)) - offset1;
        char[] stringChars = new char[length];
        for (int i = 0; i < length; i++) {
            int offset = offset1 + i;
            int indexIndex = offset % 8192;
            int index = indexChunks[offset / 8192].charAt(indexIndex) & USER_MASK;
            int charIndex = index % 8192;
            stringChars[i] = charChunks[index / 8192].charAt(charIndex);
        }
        return new String(stringChars);
    }

     public static void main(String []args){
        System.out.println(getString(0));
     }
}

중간에 SupportMenu.USER_MASK라는 변수를 사용하는데, 이 변수는 import android.support.v4.internal.view.SupportMenu; 구문을 따라 가보면 65535임을 쉽게 확인할 수 있다.

위 코드를 실행해보면 바로 flag를 확인할 수 있다.

Flag : gigem{hidden_81aeb013bea}

'writeups > Reversing' 카테고리의 다른 글

Snakes over cheese  (0) 2019.11.25
Secrets  (0) 2019.11.25
KeyGenMe  (0) 2019.11.25
rock  (0) 2019.11.25
pyc decompile  (0) 2019.11.25

Description

Category: Reversing

Source: TAMUctf 2019

Points: 494

Author: Jisoon Park(js00n.park)

Description:

nc rev.tamuctf.com 7223

Difficulty: medium

keygenme

Write-up

주어진 파일을 실행해보면 product key를 넣으라고 하는데, 대충 아무거나 넣어 봤지만 별다른 출력이 나오지 않았다.

디컴파일을 통해 어떻게 돌아가는지 살펴보자.

main 함수를 보면 입력 받은 fgets()로 입력받는 값을 verify_key() 함수를 통해 검사하고 있다. 이 함수만 통과하면 알아서 flag를 보여주는 구조다.

verify_key() 함수는 enc() 함수를 통해 입력받은 값을 인코딩 하고, 인코딩 결과가 **[OIonU2_<__nK<KsK**와 동일한지 확인하는 동작을 한다.

enc() 함수는 문자열을 한글자씩 변환하서 돌려주는 코드인데, 이 변환을 역으로 수행하면 입력해야 할 값을 찾을 수 있을 것이다.

간단하게 python을 이용해서 enc() 함수의 역함수를 작성해보자.

def dec(a1):
    v4 = len(a1)
    v2 = 72
    r = ""
    for i in range(v4):
        for j in range(32, 127):
            t = ((j + 12) * v2 + 17) % 70 + 48
            if t == ord(a1[i]):
                r += chr(j)
                break
        v2 = ord(a1[i])
    return r

fgets() 함수는 입력 받을 때 줄바꿈('') 문자 까지 입력 받으니, 마지막 한 글자를 제외하고 dec() 함수에 넣어주면 된다.
(이 부분을 놓쳐서 정상적으로 dec가 되어도 패스가 안되는 바람에 한참을 디버깅했다.)

target = "[OIonU2_<__nK<KsK"
d = dec(target[:-1])
print "dec : " + d
e = enc(d + "\n")
print "enc : " + e

if e == target:
    print "OK!"
else:
    print "Fail!"

코드를 실행시켜서 입력해야 할 값을 찾아보자.

문제에서 주어진 서버에 이 값을 보내면 flag를 얻을 수 있다.

Flag : **gigem{k3y63n_m3?_k3y63n_y0u!}**

'writeups > Reversing' 카테고리의 다른 글

Secrets  (0) 2019.11.25
Local News  (0) 2019.11.25
rock  (0) 2019.11.25
pyc decompile  (0) 2019.11.25
Easyhaskell  (0) 2019.11.25

Description

Category: Web

Source: webhacking.kr

Points: 100

Author: Jisoon Park(js00n.park)

Description:

Write-up

Password를 맞추는 문제인것 같은데, 문제만 봐서는 Password를 알아낼 길이 없다.

일단 소스 코드를 보도록 하자.

<html>
<head>
<title>Challenge 54</title>
</head>
<body>
<h1><b>Password is <font id=aview></font></b></h1>
<script>
function run(){
  if(window.ActiveXObject){
   try {
    return new ActiveXObject('Msxml2.XMLHTTP');
   } catch (e) {
    try {
     return new ActiveXObject('Microsoft.XMLHTTP');
    } catch (e) {
     return null;
    }
   }
  }else if(window.XMLHttpRequest){
   return new XMLHttpRequest();
 
  }else{
   return null;
  }
 }

x=run();

function answer(i)
{
x.open('GET','?m='+i,false);
x.send(null);
aview.innerHTML=x.responseText;
i++;
if(x.responseText) setTimeout("answer("+i+")",100);
if(x.responseText=="") aview.innerHTML="?";
}

setTimeout("answer(0)",10000);

</script>
</body>
</html>

가장 먼저 run 함수가 보이는데, 코드를 보면 XMLHttpRequest() 객체임을 알 수 있다. 서버에 뭔가를 request해서 받아오는 소켓 같은 건가보다.

그리고 answer 함수가 있는데, 마지막에 보면 10초 후에 answer(0)를 호출하도록 되어 있다.

answer 내부를 살펴보면, i를 1씩 증가시키면서 setTimeout() 함수를 이용해 0.1초마다 answer(i)를 호출하고 있는 것을 알 수 있다.

i를 증가시켜 가다가 서버에서 더이상의 응답을 보내주지 않으면 ?를 출력하고 끝내는것까지이다.

뭔가 공격자가 끼어들 건덕지가 없는 것 같다. 다시 문제 페이지로 돌아가서, 페이지를 새로 고침하고 기다리면 10초 정도 후에 글자가 하나 나타나고, 잠깐씩의 텀을 두면서 계속 바뀌어 나가는 것을 볼 수 있다.

마지막에 ?가 출력될때까지 보이는 문자열을 순서대로 기록하고, 이를 auth 페이지에 입력하면 이 문제에 대한 점수를 획득할 수 있다.

(다른 사람들의 writeup을 보았을 때, Password는 자주 바뀌는것 같다.)

'writeups > Web' 카테고리의 다른 글

Stop and Listen  (0) 2019.11.25
ReadingRainbow  (0) 2019.11.25
webhacking.kr 024  (0) 2019.11.25
webhacking.kr 027  (0) 2019.11.25
webhacking.kr 017  (0) 2019.11.25

Description

Category: Web

Source: webhacking.kr

Points: 150

Author: Jisoon Park(js00n.park)

Description:

Write-up

SQL INJECTION 문제이다.

페이지 소스를 보면 index.phps가 제공된다고 쓰여있으므로, 일단 한번 열어보자.

<html>
<head>
<title>Challenge 27</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get action=index.php>
<input type=text name=no><input type=submit>
</form>
<?
if($_GET[no])
{

if(eregi("#|union|from|challenge|select|\(|\t|/|limit|=|0x",$_GET[no])) exit("no hack");

$q=@mysql_fetch_array(mysql_query("select id from challenge27_table where id='guest' and no=($_GET[no])")) or die("query error");

if($q[id]=="guest") echo("guest");
if($q[id]=="admin") @solve();

}

?>
<!-- index.phps -->
</body>
</html>

no=([입력값]) 부분에 전송한 입력이 들어가는데, 바로 윗라인에 이런저런 필터가 있다.

특이한 점은 입력값을 괄호가 싸고 있다는 점인데, 필터를 보면 닫는 괄호는 필터링 하지 않는 것을 알 수 있다. 대충 괄호를 닫고 뒤의 괄호는 주석처리 하라는 뜻인것 같다.

불러와야 하는 id는 admin인데, where 절에서 id='guest' and no=() 라고 되어있으므로, or 구문을 만들어서 admin을 선택하면 될것 같은데, 등호(=) 기호도 필터링 되고 있어서, 비슷하게 사용되는 like 문을 이용하였다.

일단 문제 페이지에서 이런저런 숫자를 넣어보면 guest의 no는 1인것을 알 수 있고, admin은 대충 0 아니면 2일 것을 예상해 볼 수 있다.

앞부분이 true가 되면 안되기 때문에 1이 아닌 값으로 시작해서 공격벡터를 만들면 된다. 아래와 같은 값을 넣어 보면 문제를 풀 수 있다.

0) or no like 2 -- 

(-- 기호 뒤에 공백을 반드시 넣어줘야 주석문이 제대로 동작한다.)

like를 알면 금방 풀고 모르면 알때까지 못푸는 문제인듯...

'writeups > Web' 카테고리의 다른 글

ReadingRainbow  (0) 2019.11.25
webhacking.kr 054  (0) 2019.11.25
webhacking.kr 024  (0) 2019.11.25
webhacking.kr 017  (0) 2019.11.25
webhacking.kr 018  (0) 2019.11.25

Description

Category: Web

Source: webhacking.kr

Points: 100

Author: Jisoon Park(js00n.park)

Description:

Write-up

아무것도 안했는데 잘못된 IP라고 나온다... 일단 페이지 소스를 보자.

<html>
<head>
<title>Challenge 24</title>
</head>
<body>
<table border=1><tr><td>client ip</td><td>116.120.157.228</td></tr><tr><td>agent</td><td>Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36</td></tr></table><p><hr><center>Wrong IP!</center><hr>


<!--

source : index.phps

-->

</body>
</html>

index.phps파일을 열어보면 php 코드를 볼 수 있다고 한다.

<html>
<head>
<title>Challenge 24</title>
</head>
<body>
<?

extract($_SERVER);
extract($_COOKIE);

if(!$REMOTE_ADDR) $REMOTE_ADDR=$_SERVER[REMOTE_ADDR];

$ip=$REMOTE_ADDR;
$agent=$HTTP_USER_AGENT;


if($_COOKIE[REMOTE_ADDR])
{
$ip=str_replace("12","",$ip);
$ip=str_replace("7.","",$ip);
$ip=str_replace("0.","",$ip);
}

echo("<table border=1><tr><td>client ip</td><td>$ip</td></tr><tr><td>agent</td><td>$agent</td></tr></table>");

if($ip=="127.0.0.1")
{
@solve();
}

else
{
echo("<p><hr><center>Wrong IP!</center><hr>");
}
?>



<!--

source : index.phps

-->

</body>
</html>

ip라는 변수의 값을 "127.0.0.1"로 맞춰주면 될것 같다.

ip는 REMOTE_ADDR이라는 변수에서 가져오는데, 기본값은 requester의 IP 주소로 설정되는것 같다.

(extract 함수는 dictionary 형식의 데이터를 변수와 변수의 값으로 풀어헤쳐주는(?) 동작을 한다.)

extract(_SERVER)extract(_COOKIE)가 호출되므로, COOKIE에 REMOTE_ADDR를 넣어주면 ip 변수의 값을 조절할 수 있을 것 같다.

COOKIE에 REMOTE_ADDR=127.0.0.1을 바로 넣어주면 이후의 str_replace() 구문을 통과하면서 1만 남는다. str_replace() 구문을 통과했을 때 의도했던 문자열이 남도록 "112277..00..00..1"을 넣어주면 "127.0.0.1"이 남으면서 문제를 해결할 수 있게 된다.

원래 문제를 해결했을 때 뭐라고 나왔었는지는 기억나지 않는다.(...)

'writeups > Web' 카테고리의 다른 글

webhacking.kr 054  (0) 2019.11.25
webhacking.kr 027  (0) 2019.11.25
webhacking.kr 017  (0) 2019.11.25
webhacking.kr 018  (0) 2019.11.25
webhacking.kr 020  (0) 2019.11.25

Description

Category: Web

Source: webhacking.kr

Points: 200

Author: Jisoon Park(js00n.park)

Description:

Write-up

javascript challenge라고 한다. 일단 코드를 봐야겠다.

<html>
<head>
<title>Challenge 20</title>
<style type="text/css">
body { background:black; color:white; font-size:10pt; }
input { background:silver; color:black; font-size:9pt; }
</style>
</head>
<body>
<center><font size=2>time limit : 2</font></center>
<form name=lv5frm method=post>
<table border=0>
<tr><td>nickname</td><td><input type=text name=id size=10 maxlength=10></td></tr>
<tr><td>comment</td><td><input type=text name=cmt size=50 maxlength=50></td></tr>
<tr><td>code</td><td><input type=text name=hack><input type=button name=attackme value="fhyjznwusm"
 style=border:0;background=lightgreen onmouseover=this.style.font=size=30 onmouseout=this.style.font=size=15></td></tr>
<tr><td><input type=button value="Submit" onclick=ck()></td><td><input type=reset></td></tr>
</table>
<script>
function ck()
{

if(lv5frm.id.value=="") { lv5frm.id.focus(); return; }
if(lv5frm.cmt.value=="") { lv5frm.cmt.focus(); return; }
if(lv5frm.hack.value=="") { lv5frm.hack.focus(); return; }
if(lv5frm.hack.value!=lv5frm.attackme.value) { lv5frm.hack.focus(); return; }

lv5frm.submit();

}
</script>

<br>

do not programming!<br>

this is javascript challenge

</body>
</html>

nickname과 comment에 적당한 값을 넣고 code에 바로 옆에 있는 텍스트를 똑같이 넣으면 submit이 정상적으로 수행된다.

submit 후에 특별한 동작은 없고(잠깐 Wrong이라는 메세지가 보였다가 사라진다.), 해당 페이지가 새로고침 되는데, code에 넣어야 할 값은 이전과 다른 값으로 변경된다. (페이지를 그냥 새로고침해도 마찬가지이다.)

자동으로 계속 submit을 하도록 하면 해결되는 문제인가 싶기도 하지만, 바로 아래에 programming이 아니라고 하는걸 보니 그렇게 푸는건 아닌가보다. 다른 방향을 고민해 보자.

아무리 생각해도 다른 방향은 안떠오르는데, 위에 보면 "time limit : 2"라는 문구가 있다. 2초 안에 submit을 해야하나 보다.

매번 다르게 들어오는 문자열을 어떻게 바로 회신할 수 있을지.. python으로 proxy를 짜야하나 아니면 chrome의 개발자 도구에 이벤트를 추가하거나 하는 방법이 있나 고민해보았지만 마땅치가 않아서 burp suite를 이용했다.

위 그림과 같이, script 태그가 감지되면 form을 채우고 바로 ck 함수를 부르는 코드를 삽입하도록 하였다.

이후 다시 문제 페이지를 불러오면 페이지가 계속 리로딩이 되는데(당연히), response를 보면 문제를 해결했다는 회신을 확인할 수 있다.

근데 이런식이면 programming이 아니라는 말은 구라 아닌가...

'writeups > Web' 카테고리의 다른 글

webhacking.kr 027  (0) 2019.11.25
webhacking.kr 024  (0) 2019.11.25
webhacking.kr 017  (0) 2019.11.25
webhacking.kr 018  (0) 2019.11.25
type confusion  (0) 2019.11.25

+ Recent posts