'SQL Injection'에 해당되는 글 6건
- 2018.02.21 [webhacking.kr] prob45(550pt)
- 2018.01.26 [webhacking.kr] prob46(300pt)
- 2018.01.18 [webhacking.kr] prob8(350pt)
- 2018.01.12 [webhacking.kr] prob18(100pt)
- 2016.09.08 [LOS] level1 cobolt(주석)
- 2016.09.07 [LOS] level1 gremlin(simple sql injection)
## prob45(web, 550pt)
[Main]
45번 문제는 sql injection 문제라고 문제 페이지에 나와있었습니다. 우선 문제 페이지와 소스코드를 보면 아래 [그림 1], [그림 2]와 같습니다.
[그림 1] 문제 페이지
[그림 2] index.phps
우선 admin으로 로그인하기 위해 "select id from members where id='$_GET[id]' and pw=md5('$_GET[pw]')" 문에서 sql injection을 시켜 결과 값이 admin이 되도록 해야합니다. 각각의 GET방식의 변수에는 별도의 필터링이 걸려있는데, "select id from members where id='asdf' or id='admin'#' and pw=md5('asdf')"과 같은 식으로 injection을 하면 될 것이라고 생각했습니다.
하지만 $_GET[id]에는 admin이 필터링으로 걸려 있기 때문에 "select id from members where id='asdf' or id=0x61646d696e#' and pw=md5('asdf')"와 같이 고쳐 우회할 수 있습니다. 하지만 한 가지 문제가 더 있습니다. php의 설정 중 magic_quotes_gpc가 on으로 되어 있으면 single_quote('), double_quote("), slash(/)가 입력되면 그 앞에 "\"(역슬래시)가 붙어 문자열로 인식시켜주는 sql injection 보호기법 입니다. 그런데 이 문제는 이 보호기법이 걸려있었습니다.
그래서 이를 우회할 수 있는 취약점이 php의 함수 중 mb_convert_encoding()이라는 함수에 있습니다. 이 함수는 문자열의 인코딩 방식을 변경하는 php 함수입니다. 취약점은 2바이트가 멀티바이트로 인식되어 일반적인 아스키로 표시할 수 없는 문자를 표시하도록 하는 곳에 있습니다. 예를 들면 "%aa\"가 하나의 문자로 인식되어 버리는 것입니다.
따라서 "select id from members where id='%aa' or id=0x61646d696e#' and pw=md5('asdf')"와 같이 입력하면 "select id from members where id='%aa\' or id=0x61646d696e#' and pw=md5('asdf')"로 변하면서 "\"(백슬래시)때문에 single quote가 문자열로 인식되는것을 막을 수 있습니다. 이렇게 쿼리를 날리면 아래 [그림 3]과 같이 문제가 풀리게 됩니다.
[그림 3] Conratulations~!
'Wargame > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] prob51(250pt) (1) | 2018.02.21 |
---|---|
[webhacking.kr] prob26(100pt) (0) | 2018.02.21 |
[webhacking.kr] prob5(300pt) (0) | 2018.02.21 |
[webhacking.kr] prob33(200pt) (0) | 2018.02.21 |
[webhacking.kr] prob4(150pt) (0) | 2018.02.21 |
## prob46(web, 300pt)
[Main]
46번 문제는 sql injection 문제였는데 mysql의 string관련 내장함수를 잘 이용하거나 mysql특징을 잘 알면 풀 수 있는 문제였습니다. 우선 문제를 보도록 하겠습니다.
[그림 1] 문제 페이지
우선 대놓고 문제 페이지에서 SQL INJECTION이라고 적혀있습니다. 소스코드보기를 하면 index.phps가 주석으로 나와 있는데 index.phps에서 페이지 소스를 보면 아래 [그림 2]와 같습니다.
[그림 2] index.phps
위 소스코드를 잘 보면 공백 문자, '/', '*', '%'를 str_replace()함수로 필터링하고 있으며, 아래 eregi()함수를 이용하여 "union", "select", "from", "challenge", "0x", "limit", "cash" 문자열들을 필터링하고 있습니다. 그리고 그 아래에서는 가장 중요한 sql 쿼리문("select id, cash from members where lv=$_GET[lv]")이 보입니다. 우선 lv에 0도 넣어보고, 1도 넣어보고, 2도 넣어보고 해봤는데 1만 값이 출력되는 걸로 봐서, lv가 1인 경우밖에 없나보다라고 생각했습니다.
자, 이제 sql injection을 할 차례입니다. 처음에는 lv변수가 숫자이므로 싱글 쿼터를 쓰지 않아도 된다는 점은 좋았습니다.(왜냐하면.. 싱글 쿼터를 써봤는데 아래 싱글쿼터가 php의 보안 설정인 magic_quotes_gpc가 on되어 있어서 싱글쿼터 앞에 '\'를 자동으로 붙이게 되어 sql 쿼리문에서 먹히지 않았습니다...) 그래도 문제를 쉽게 풀려면 "select id, cash from members where lv=0 or id='admin'"이렇게 해야하지만 싱글쿼터를 쓸 수 없으니.. 이 방법은 빠르게 접었습니다. 그리고 우선은 공백 문자 필터링을 우회해야하는데 처음엔 '%'를 필터링하니까 %0a를 사용할 수 없겠구나 라고 생각했지만 해보니 됐습니다.(왜 그런지는 아직 잘..) 이렇게 %0a로 공백문자를 우회하고 나니까 "select id, cash from members where lv=0%0aor%0alv=1"과 같은 식의 injection을 테스트 할 수 있었습니다. 잘 먹히는게 확인되었습니다.
그래서 싱글쿼터를 안하고 이것 저것 시도해보다가 "select id, cash from members where lv=1%0aand%0alength(id)=8"과 같은 구문을 시도해봤는데 아래 [그림 3]과 같이 [그림 1]과는 길이가 8인 다른 아이디가 출력되는 것을 확인할 수 있었습니다.
[그림 3] 첫 번째 시도
흠.. 생각해보니까 MySql에서 싱글쿼터를 쓰지 않고 문자를 표현할 때 'admin'=0x61646D696E 처럼 16진수로 나타내도 된다고 알고 있는데, "0x"가 필터링 되서 못쓴다고 생각했지만 0x가 되면 0b도 되지 않을까 해서 아래 [그림 4]와 같이 "select id, cash from members where lv=1%0aand%0aid=0b110000101100100011011010110100101101110"을 입력했더니 문제가 풀렸습니다.
[그림 4] Congratulation(1)
흠 근데 생각해보니 mysql의 string관련 내장 함수를 쓰면 이렇게 말고도 풀 수 있을 것 같아 https://dev.mysql.com/doc/refman/5.7/en/string-functions.html 여기를 뒤적거리다보니 쓸만한 함수가 나왔습니다. char()함수입니다. 위 url의 메뉴얼에 따르면 char(97,100,109,105,110)='admin'이라고 합니다. 그래서 아래 [그림 5]처럼 injection하면 짜잔! 풀립니다.
[그림 5] Congratulation(2)
'Wargame > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] prob4(150pt) (0) | 2018.02.21 |
---|---|
[webhacking.kr] prob1(200pt) (0) | 2018.02.21 |
[webhacking.kr] prob25(150pt) (0) | 2018.01.26 |
[webhacking.kr] prob20(200pt) (0) | 2018.01.19 |
[webhacking.kr] prob8(350pt) (0) | 2018.01.18 |
## prob8(web, 350pt)
[Main]
8번 문제는 간단한 sqli 문제였습니다. 우선 문제페이지와 소스코드를 보면 아래 [그림 1]과 같습니다.
[그림 1] 문제 페이지와 소스코드
우선 위 [그림 1]에서 소스코드에 보면 주석으로 "index.phps"라고 되어 있습니다. 그래서 이 힌트를 바탕으로 index.phps로 접속하면 아래 [그림 2]와 같은 index.php 소스코드를 확인할 수 있습니다.
[그림 2] index.php 소스코드
우선 우리가 주의 깊게 보아야 할 부분은 위에서 네모 박스부분입니다. 최종적으로 우리가 해야할 부분은 5번인데 3번이 포함된 select문의 결과로 id가 admin이 나오도록 해야합니다.
이런 sqli문제를 풀때 기본적으로 우리가 조작할 수 있는 input을 파악해야하는데 소스코드를 보면 $agent라는 변수가 "HTTP_USER_AGENT"값을 받아오고, 이와 같은 값인 $_SERVER[HTTP_USER_AGENT]를 수정할 수 있습니다. 따라서 3번과 4번을 조작할 수 있고 sqli 취약점이 발생하게 될 것입니다.
그런데 한가지 문제가 발생하는데 $agent를 조작할 수 있지만 1번에 의해 "."과 "/"가 "_"로 치환되고, $pat에 정의된 정규표현식에 의해 필터링되고 있으며, $agent와 같은 값을 가지는 $_SERVER[HTTP_USER_AGENT]도 2번에 의해 single quote와 "\"가 필터링되고 있습니다. 따라서 3번의 SQL 쿼리문에서 발생하는 sqli 취약점은 싱글 쿼터와 역슬래시를 사용할 수 없고, 4번의 SQL 쿼리문에서 발생하는 sqli 취약점은 "."과 "/"를 포함한 $pat에 매치되는 문자를 사용할 수 없습니다.
여기서 저는 3번을 이용하여 문제를 풀기 위해서는 싱글쿼터로 sql 쿼리문을 필수적으로 닫아주어야 하는데 이게 필터링 되면서 실질적으로 sqli를 이용하기가 힘들다고 판단하였습니다. 하지만 4번을 이용하여 sqli를 이용할 때는 싱글 쿼터와 ","와 ")"와 "#"(주석)이 이용 가능하다는 점을 이용하여 sql injection을 합니다. 우리의 목표는 3번 select문의 결과, id가 "admin"이 되도록 만들면 되므로 테이블에 admin을 insert 해주면 됩니다.
위 분석을 토대로 $agent 부분에 "wjdebug','1234','admin')#"라는 쿼리문을 injection 시키면 "insert into lv0(agent,ip,id) values('wjdebug','1234','admin')"이라는 쿼리가 완성되어 id가 "admin"인 행이 생기게 됩니다. 이렇게 인젝션을 시키기 위해 아래 [그림 3]과 같이 burpsuite라는 프록시 도구를 이용해 USER_AGENT부분에 원하는 injection payload를 삽입합니다.
[그림 3] Sql injection Payload 삽입
이제 [그림 2]에 있는 3번의 $agent에 wjdebug만 입력하면 그에 대응되는 id의 내용이 select의 결과로 나오는데 이것은 아까 insert문으로 'admin'으로 만들었기 때문에 'admin'이 반환되며 아래 [그림 4]와 같이 문제를 풀었다는 html을 리턴해냅니다.
[그림 4] congratulation!
참고로 위 처럼 burpsuite의 repeater 탭 기능을 사용할 때 우측 상단의 target을 설정해주어야 합니다. 그리고 request는 한번 proxy로 잡아서 내용을 복붙해서 사용하면 됩니다.
'Wargame > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] prob25(150pt) (0) | 2018.01.26 |
---|---|
[webhacking.kr] prob20(200pt) (0) | 2018.01.19 |
[webhacking.kr] prob21(250pt) (0) | 2018.01.13 |
[webhacking.kr] prob18(100pt) (0) | 2018.01.12 |
[webhacking.kr] prob17(100pt) (0) | 2018.01.12 |
## prob18(web, 100pt)
[Main]
18번 문제는 아주 간단한 SQLi 문제였습니다. 우선 문제를 보면 아래와 같은 페이지를 볼 수 있습니다.
[그림 1] 문제 페이지
일단 index.phps라는 이 문제 페이지의 php 소스로 가는 링크를 클릭하면 아래 [그림 2]와 같이 php 소스 코드를 볼 수 있습니다.
[그림 2] index.phps
소스 코드에서는 eregi()함수를 이용해 간단한 필터링을 합니다. 그리고 "select id from challenge18_table where id='guest' and no=$_GET[no]"라는 쿼리문을 실행시키는데 where 절안에 no파라미터를 GET방식으로 받아서 포함시킵니다. 일단 no 컬럼은 숫자이므로 아무 숫자나 0, 1, 2, 3...을 집어넣어 봤습니다. 1을 넣으니 "hi guest"가 떳고, 나머지는 아무것도 안떴습니다. 여기서 guest 계정은 no 컬럼이 1이라는 것을 알 수 있습니다.
여기에 sql injection이 가능하고 따라서 "~ where id='guest' and no=-1 or no=2"로 쿼리를 인젝션시키면 (id='guest' and no=-1)이 false가 되고 or로 묶인 no=2가 true가 되면서 결과 값이 나오게 됩니다. 여기서 no=2는 admin 계정입니다. no=2가 admin이라는 것은 0부터 차례대로 입력해보았습니다. 그리고 공백 문자가 필터링되고 있으므로 공백문자를 공백문자 우회할 수 있는 방법들(%0a, %09, %0d, /**/, +)중 하나인 %0a로 대체하여 쿼리(-1%0aor%0ano=2)를 날리면 아래 [그림 3]과 같이 문제가 풀립니다.
[그림 3] Congratulation!
참고로 "id='guest' and no=1 or no=2"로 인젝션시키면 guest가 결과로 나오게 되므로 id='guest'를 무력화시켜줘야 합니다. 그리고 id='admin'을 인젝션 쿼리에 넣어 바로 실행시키려고 했지만 싱글 쿼터가 url encode되어 쿼리문을 실행시킬 수 없었습니다
'Wargame > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] prob20(200pt) (0) | 2018.01.19 |
---|---|
[webhacking.kr] prob8(350pt) (0) | 2018.01.18 |
[webhacking.kr] prob21(250pt) (0) | 2018.01.13 |
[webhacking.kr] prob17(100pt) (0) | 2018.01.12 |
[webhacking.kr] prob10(250pt) (0) | 2018.01.12 |
## LOS level1 cobolt(주석)
2번째 문제를 보자.
아래와 같은 소스코드를 볼 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php include "../config.php"; login_chk(); dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysql_fetch_array(mysql_query($query)); if($result['id'] == 'admin') solve("cobolt"); elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; highlight_file(__FILE__); ?> | cs |
소스코드를 보면 위 쿼리문을 통한 결과 값의 id컬럼이 admin이어야 한다.
우선 쿼리문을 보면 우리가 입력 가능한 파라미터는 id, pw부분이다. id 부분에 1번 문제와 비슷하게 쿼리를 날리는데 id값이 admin인 것의 결과를 뽑아와야 하므로 admin'%20or%201=1--%20 쿼리를 날리면 될거라고 생각했다. 그랬더니 아래 [그림 1]과 같은 결과가 나타났다.
[그림 1] 1차 시도
1차 시도는 실패였다.
이런 결과가 나타나는 이유는 where id='admin'이라는 조건문이 있지만 뒤의 or 1=1--때문에 그냥 참인 값만 반환을 하여 id가 admin인 것의 결과를 반환하는 것이 아니라 그냥 테이블에 들어간 순서대로 뽑아냈기 때문에 rubiya가 뽑힌 것이다.
따라서 추가로 id파라미터에 id=admin'%20or%201=1%20and%20id='admin'%20--%20을 넣어주면 id가 admin인 결과를 반환한다.
최종 페이로드는 http://los.sandbox.cash/chall/cobolt_c1c72102d0334847a38123e460f27f8c.php?id=admin%27%20or%201=1%20and%20id=%27admin%27--%20 와 같고 쿼리를 날리면 아래 [그림 2]와 같이 문제가 풀리는 것을 확인 할 수 있다.
[그림 2] Cobolt Clear!
=> 정리 : 그냥 admin'%20--%20으로 주석만 써도 된다.
'Wargame > LOS(level1)' 카테고리의 다른 글
[LOS] level1 gremlin(simple sql injection) (0) | 2016.09.07 |
---|
## LOS level1 gremlin(Simple SQLi)
LOS는 Lord of SQL injection의 약자로 Lord of Bufferoverflow를 모티브로 만들어진 webhacking을 다루는 워게임 사이트이다. 첫 번째 문제를 보자.
[그림 1] 문제(몹) 리스트
우선 첫 번째 문제의 이름은 gremlin이다. 몬스터를 클릭하면 소스코드가 나오는데 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 | <?php include "../config.php"; login_chk(); dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); // do not try to attack another table, database! if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysql_fetch_array(mysql_query($query)); if($result['id']) solve("gremlin"); highlight_file(__FILE__); ?> | cs |
GET방식으로 id와 pw라는 파라미터를 받는데 주어진 쿼리문은 select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"이다. 문제를 풀기 위해서는 10번째 라인에서 $_result['id']에 값이 들어 있기만 하면 되므로 id파라미터로 '%20or%201=1--%20 정도의 쿼리문만 넣어도 위 쿼리문의 where절은 항상 참이게 되므로 테이블에 값이 있으면 가장 위의 컬럼을 반환한다.
이렇게 변환된 쿼리문을 구성해보면 아래와 같다.
"select id from prob_gremlin where id='' or 1=1-- ' and pw=''";
결과적으로 위 페이로드대로 구성하여 request를 날리면 아래 [그림 2]와 같이 문제가 풀리게 된다.
[그림 2] Gremlin Clear!
'Wargame > LOS(level1)' 카테고리의 다른 글
[LOS] level1 cobolt(주석) (0) | 2016.09.08 |
---|