Lab: Web shell upload via extension blacklist bypass 문제 풀이

이번 문제는 Blacklist에 관한 문제이다. Blacklist란 특정 단어만을 필터링하여 입력되지 못하게 하는 것이다. 지금까지는

php파일을 서버에 올려서 올린 파일의 위치를 찾아 실행만 시키면 php가 작동되었다. 이번에는 Blacklist 필터링을 했기 때문에 아마 안올라갈 가능성이 높다.

실제로 아래 php 를 올려보니 확장자명이 필터링되어 승인이 거절되는 것을 볼 수 있었다.

이제 업로드 요청을 burp suit Repeater 보내 확장자명을 우회해 보자 우선 첫번째로 생각해 보면 File upload 문제 3 에서 설명한 것과 같이 php 말고 다양한 확장자명이 존재한다. 이 중 선택적으로 승인하여 받아들이는 것이 가능하기 때문에 여러 확장자 명을 대입해 어떠한 확장자가 승인되는지 확인해봐야한다.

우선 아래 사진에 나온 php 확장자를 대입해 보겠다. 

그 결과 아래 처럼 php를 제외한 거의 모든 확장자가 올라가는 것을 보았다. 이 페이지의 경우 php만 필터링하는 것으로 예상된다.

이 문제의 경우 우회가 너무 쉬웠다.

오늘은 한문제 더 풀어보도록 하겠다.

Lab: Web shell upload via obfuscated file extension 문제풀이

이번 파일의 경우 php를 다이렉트로 파일 업로드를 했지만 아래와 같이 JPG, PNG 파일만 업로드가 가능하다고 되었다. 이 문제도 위와같이 우회를 우선 해보겠다.

모든 우회가 실패하였다. 이번 문제의 경우 png와 jpg의 이름만을 화이트 리스트로 허용하는 것으로 예상된다. 이를 뚫기 위해 파일명을 png를 붙여주돼 서버에 올라갈때는 php라는 파일로 올라가도록 이름을 변경해 보았다.

exploit.php%00.png 여기서 %00는 종단 문자로 뒤에 문자는 무시한다는 의미이다. 이 파일을 서버에 올리면 아래와 같이 성공적으로 올라가는 것을 알 수 있었다.

 업로드한 파일 내용에는 php문구가 포함되어 있기 때문에 실행하면 flag가 나오게 된다.

 

Lab: Web shell upload via path traversal 문제풀이

해당 페이지에 들어가 로그인을 하게 되면 파일 업로드가 가능하다. 이번 문제에서는 이것을 이용하여 웹 쉘을 만들어야 한다.

아래는 파일을 업로드하였을때 발생하는 요청을 확인한 것이다. 내용을 보게되면 이미지 데이터를 읽어와 서버로 보내는 것을 확인할 수 있다.

그리고 내가 업로드한 이미지를 우클릭하여 경로 복사하면 아래 처럼 경로가 files/avatars/cat1.jpg로 나오는 것을 알 수 있다.

https://bb7c0d2448900c3005c.web-security-academy.net/files/avatars/cat1.jpg

이를 이용해 아래와 같이 filenmae과 내용을 system이라는 쉘을 만들어 업로드해 실행시켜보았다.

하지만 화면상으로 보여지기만 하지 실행되지 않았기 때문에 이 경우 첫번째로 생각할 수 있는 경우는 확장자를 지정하여 특성 확장자만 실행되도록 코드가 짜져있기 때문에 이를 위회하기 위해서 모든 종류의 확장자를 대입해 보아야 한다. php의 경우  아래 처럼 여러 확장자가 존재한다.

위 확장자로 다 대입을 하였는데 안되었다. 이 경우 php라는 단어를 자체를 필터링하여 올리는 경우가 존재하기 때문에

phphpp 같은 형식의 확장자로 올려도 보았지만 작동안하는 것은 매한가지 였다.

그래서 생각해 낸게 해당 폴더에서는 읽기만 가능하도록 권한 설정한 것으로 파악하여 다른 경로에 파일을 저장하도록 하였다. 서버가 작동하기 위해서는 php 파일을 무조건 읽어야하기 때문이다.

그래서 파일 이름을 ../name.php 라는 형식으로 적어 해당폴더 전 경로에 name.php를 저장하게 하였다.

그랬더니 아래와 같이 ../써도 name.php라고 적혀있을 것을 볼 수 있다. 다른 위치에 /를 넣으면 자동으로 해당 위치 위로 파일이름을 잘라내는 것 같았다. 이는 인코딩 후 잘라낸다음에 디코딩하는 것으로 예상이 되어 미리 인코딩한 것을 넣고 디코딩시 해당 / 문자를 인식하지 못하도록 하여 잘라내지 못한 상태로 디코딩하여 입력과 똑같이 나오도록하였다.

url에서 / 인코딩은 %2f 이고 아래에 정리를 해놓았다.

%26 &
%2F /
%3A :
%3F ?
%3D =

..%2fname.php 로 하였더니 정상적으로 avatars/../name.php의 경로에 저장되었다. (../)라는 문자는 전 폴더에 저장하라는 위치이니 avatars가 있는 경로에 저장된 것을 확인할 수 있다.

아래와 가이 files라는 경로에서 flag를 찾아내었다.

Lab: Web shell upload via Content-Type restriction bypass 문제 풀이

아래는 해당 문제 풀이 사이트에 들어가 이미지 파일을 올려보았더니 페이지에 이미지가 보이고 있다. 원하는 파일을 올릴 수 만 있다면 웹 쉘을 획득할 수 있을 것이다.

파일 전송한 페이지를 보니 아래와 같이 content-type이 image/png 라고 적혀 있다 이는 파일의 형식을 포함하여 서버로 전달하는 것을 볼 수 있다. 이는 이미지 파일의 경우 자신이 무슨종류의 파일인지 포함하는 데이터를 가지고 있기 때문에 이를 클라이언트에서 읽어서 같이 서버로 올린 것으로 파악된다.

그렇기 때문에 php 파일이 업로드가 막힌 경우 content -type을 변경하여 서버로 올리면 되는 것이다.

이제 홈으로 가면 이미지불러오는 코드로 해당 경로에서 이미지 파일을 불러오는 것을 알 수 있다.

이제 경로만 알아내면 되는데 어디로 저장되는지를 파악해야한다. 이를 위해 해당 이미지를 불러오는 사이트에서 경로를 파악해야한다.

위 이미지와 아래 이미지는 같은 것으로 위는 아래 코드가 실행된 것이다. 여기서 내가 올린 이미지 파일이 <image 태그를 통해 불러오는데 src에 이 경로가 적혀있다. 이 경로를 적어주기만 하면 이미지 파일을 불러올 것이다.

test1.php 를 업로드하는데 아래에는 해당 파일의 내용이 담겨져 있다. 하지만 contetn-type이 image/png 이기 때문에 서버에 올라가게 될 것이다. 만약 형식이 php 이면 이것이 반려되기 때문에 이처럼 클라이언트 필터링을 파일명만 변경하여 보내먄 통과된다.

이를 Repeater에서 send하기만 하면 답이 나오게 된다.

Remote code execution via web shell upload 문제 풀이

burp suit에는 문제와 풀이가 같은 페이지에 존재해서 쉽게 답안지를 볼 수 있다. 하지만 최대한 끝까지 보지 않고 문제 푸는걸 권장한다. 첫 문제풀이의 경우 어렵지 않지만 방향성을 모를 수 있으니 보더라도 첫 쉬운 문제만 보고 나머지는 응용하는 것이기 때문에 응용해서 풀면 되겠다.

 

첫 문제는 /home/carlos/secret 이라는 경로에 파일이 있고 올리는 파일은 php 를 사용하라 했다. 이를 종합적으로 이용해서 문제를 풀어보자 첫 번째로 접근해야할 점은 저 경로에 무슨 파일이 있는지 알아내는 것이다.

이를 위해서는 서버와 소통해서 데이터를 가져오는 <?php ?> 문을 사용해야하고 그 안에 들어가야하는 코드는 해당 경로의 파일을 알아내는 명령어 혹인 웹셀 명령어가 들어가야할 것이다.

 

아래는 해당 문제 사이트에서 파일을 업로드 할 때 어떠한 방법으로 서버에 올리는지 burp suit를 이용하여 파악한 것으로

나는 

poo.php 라는 파일에 

<?php system($_GET['cmd']);?> 를 작성해 올렸다.

해당 코드는 쉘 코드를 작성하는 것으로 get 방식으로 cmd 에 원하는 명령어를 넣으면 작동하게 된다.

이 페이지 정보를 Repeater로 보내고 이름을 File upload로 정한다.

그렇게 되면 Reapeater에서 파일명과 파일 내 데이터를 원하는 걸로 바꿔서 올릴 수 있게 된다. 

 

이제 업로드한 파일을 테스트하기 위해서는 어느 경로로 실행되어야하는지 알아야한다.

이를 알기 위해서는 마이페이지에 이미지를 어디서 불러오는지 알아내야한다 예를들면 image 태그로 불러올 경우  src라는 경로를 지정해줘야하기 때문에 이점을 참고해서 경로를 파악해주거나 다른 이미지 파일들은 어디서 데이터를 불러오는지 확인할 수 있다면 경로를 찾을 수 있다.(무조건 다른 이미지 파일이 불러오는 경로와 내가 업로드한 파일 경로가 같을 수 없으니 이점도 유의해야한다.

위에 대한 자세한 내용은 2에 적어놓을 테니 그것을 보고 참고할 것!

 

이때 코드일 경우 php 서버에서 실행하게 되는데 이 때 파일을 따로 읽어주는 코드를 작성하게 되면 아래와 같이 읽어주기만 하면 된다.

하지만 이 경우 조금 다른 경우가 존재했다. 읽기는 읽히는데 system 코드가 들어갈 경우 해당 결과가 echo를 써도 나오지 않았다.

그래서  다른 방법으로 접근하였다.

(올린 파일을 작동시키는 방법은 해당 경로의 파일을 실행시키기만 하면 되기 때문에 아래와 같이 해당 경로의 파일명만 바꿔주고 실행하면 바로 실행이 되어 결과가 나오게 된다.)

system 명령어가 작동하지 않거나 block했을경우를 생각하여 다른 명령어 코드인 file_get_contents()를 집어넣었다.

아래와 같이 말이다.

<?php echo file_get_contents('/home/carlos/secret');?>

그랬더니 아래와 같이 결과가 출력되었다.

이런 문제를 풀때는 해당 서버가 어떤식으로 파일을 작동시키는지를 잘 생각해봐야한다.

Error Base SQL Injection을 이용한 Database table, column 이름 알아내기

Step 1 Error Base SQL Payload 준비

select * from userdata where name='' 은 입력받는 유저 이름에 따라 데이터를 제공하는 sql 문이다.

여기서 sql injection이 가능하다면  아래와 같은 코드를 집어넣어 에러문구에 tyrell을 포함하여 출력할 수 있다.

mario' and updatexml(null,concat(0x3a,(select 'tyrell')),null) and '1'='1 
코드가 있다면'

-> select * from userdata 
where name='mario' and updatexml(null,concat(0x3a,(select 'tyrell')),null) and '1'='1'

위 코드를 설명하자면

UPDATEXML(XML_형식, XPath_string, new_value); 

UPDATEXML의 경우 문서의 노드 값을 변경하는 함수이다. 문법은 처음 입력은 xml이 string 형식인지 doc 형식이지 등을 결정하는 칸이고 두번째 xpath는 경로로 해당 경로로 찾아가서 3번째 인자인 새로운 value 값으로 치환해준다. 만약 xpath가 틀릴 경우 xpath를 오류 설명에 포함해 함께 반환한다.

이때 xpath에 경로형식이 아닐 경우도 이 오류를 반환하는데 이를 이용하여 테이블과 컬럼명을 알아내는 것이다.

concat의 경우 문자를 이어주는 역할을 한다. 

저렇게 mario라는 계정이 있다면 name=mario는 참이고 '1'='1'도 참이기 때문에 updatexml을 실행시켜 참인지 확인하게 된다. 이때 updatexml의 경로에 0x3a 을 집어넣게 되면 경로에 문제가 생겨 자동으로 에러를 반환한다. 0x3a는 아키아2 코드의 : 라는 문자이다. 이렇게 되면 에러를 출력할 때 :tyrell을 출력하게 된다. 즉 에러 문구에 코드가 실행되어 출력되는 것이다.  맨뒤에 '1'='1' 논리연산을 확실하게 동작하기 위해서 집어넣은 것이다.

아래는 나의 logindb를 이용하여 사용한 예제이다.

보게되면 updatexml 안에 select database()를 쓴 것을 볼 수 있다. 이는 database의 이름을 출력하는 것으로 xpath syntax error를 보게되면 ':logindb'를 출력된 것을 볼수 있다. 이는 실제 database 이름과 같다는 것을 볼 수 있다.

updataxml과 비슷한 코드로는 Extractmxl이 존재한다. 

extractvalue(xml_target, xpath_expr) 로 xml_target에서 xpath_expr과 일치하는 xml 노드를 반환하는 함수이다.

이를 응용하면

select * from login where login_id='aa' and extractvalue(0x3a, concat(0x3a,(select database())));

가 될것이다. 이를 적용하면 updatexml과 같은 에러 결과가 나오게 된다. 

 

이를 이용하여 select database() 위치에 table 이름이나 열을 알아내는 코드를 넣으면 알아낼 수 있다. 이를 통해 

database의 구조를 알아내어 값을 추출해 낼 수 있는 것이 Error SQL injection이다.

Lab: SQL injection attack, querying the database type and version on Oracle

오늘은 SQL Injection 문제를 하나 풀건데 문제 내용은 database version을 알아내는 방법이다. 하나를 제대로 알면 나머지 데이터 명 또한 쉽게 알아낼 수 있으니 처음에 어렵더라도 포기하지말자.

처음 사이트에 들어가면 아래와 같이 나오게 된다

이때 search 중 gifts나 lifestyle을 클릭하면 url이 아래와 같이 형식으로 나오게 된다. category="검색데이터" 형식으로 sql을 질의하여 데이터를 가져오는 것을 볼 수 있다. 여기서 sql injection을 테스트해보면 가능하다는 것을 알 수 있다.

https://ac3e1fa21fc00b0cc07a032700830059.web-security-academy.net/filter?category=Gifts
https://ac3e1fa21fc00b0cc07a032700830059.web-security-academy.net/filter?category=Lifestyle

이 문제를 해결하기 위해서는 UNION을 사용하여 다른 select를 이어 붙여서 사용해야한다.

UNION은 다른 기존 sql문에 다른 select 문을 결합하여 출력가능하도록 하는 코드이다.

이 페이지에서는 SQL 질의의 결과가 화면에 출력되기 때문에 우리가 원하는 출력도 해당 화면에 출력하기 위해 이어 붙여서 출력하기 위해 UNION을 사용한다.

(1)UNION의 조건

UNION을 사용하기 위해서는 SELECT할 데이터와 열의 갯수가 같아야 한다. 이를 위해 우선 기존 data의 열의 갯수를 알아야하는데 이는 order by 나 select null,null을 이용하여 알아낼 수 있다.

예시
Select * from Data where category = '입력값'
위 코드에서 입력값을 'order by 2-- 넣으면
2열을 기준으로 정렬하게 된다. 만약 2열이 없다면 오류를 발생'

-> Select * from Data where category = ''order by 2--

입력값 = 'union select null,null--
union은 열이 같아야 쓸 수 있기 때문에 null을 계속 추가하다가 열의 갯수가 일치하면
오류가 안떠서 열의 갯수를 알 수있다.'

-> Select * from Data where category = ''union select null,null--

위 코드를 이용하면 열의 갯수를 알아낼 수 있고, 두번째로 해야하는 것은 데이터의 형태가 어떻게 되었냐 이다. union의 경우 열 뿐만 아니라 데이터셋도 같아야 합칠 수 있다. 그래서 위에서 null을 이용한 것인데 null의 경우 숫자와 텍스트 둘다 가능하기 때문에 null을 통해 열의 갯수를 파악하고 null 대신 하나씩 'a'의 텍스트를 넣어 데이터의 type을 알아낸다. 이를하기 위해서는 Database version의 명도 text 형식이기 때문에 text형식이 가능한 열에 출력을 해야하기 때문이다.

ex) 데이터셋

idx   name                 data

0      jame                   21

1      hoit                    31

2      tyrell                   11

4      Database version    4    <- 이와 같이 union을 이용해 합칠 데이터는 해당 열의 데이터 type이 일치해야함

 

하지만 여기 사이트에서는 order by는 작동하지만 'union select null,null-- 은 작동하지 않는다. 그 이유는 아래 oracle 튜토리얼에 나와있는데 oracle의 경우 어느 테이블에서 가져올지를 나타내는 from을 써야만 작동한다.

oracle을 알 수 있던 이유는 페이지 상단 위에 무슨 Database를 사용할지 알려줬기 때문에 알 수 있었다. 만약 없다면 모든 종류를 해봐야 할것이다.

https://www.oracletutorial.com/oracle-basics/oracle-dual-table/

 

Oracle DUAL Table: What is DUAL Table in Oracle

This tutorial introduces you to Oracle DUAL table which is a special table used for evaluating expressions or calling functions

www.oracletutorial.com

이를 위해서는 위에 사이트에서 나와있는 모든 유저들이 접근가능한 테이블을 사용해야한다. 대표적으로 dual이 있다고 글에서 소개하고 있다.

그렇다면

'union select null,null from dual-- 이렇게 해야 결과가 나오게 된다.

이를 이용하여 기존 데이터와 일치하는 열 갯수를 파악하고 위 코드에서 null 대신에 문자열을 집어넣어서 어디서Database version 명을 출력가능한지 파악한다. 아래는 Select 문을 사용하여 Database version 을 출력해야하는데 이를 알아내기 위한 select문은  https://portswigger.net/web-security/sql-injection/cheat-sheet 여기에 나와있다.

코드로 작성하게 되면

-> Select * from Data where category = ''union select banner,null from v$version--

이렇게 될 것이다.

url에 작성을 해야하기 때문에 띄어쓰기는 +로 대치해야한다.

-> https://ac941f0e1efcedb0c0af02a200e10042.web-security-academy.net/filter?category=Pets'+union+select+banner,+null+from+v$version-- 

마지막으로 --을 사용한 이유는 기존 sql where 뒤에 오는 조건을 주석처리함으로써 삽입하는 sql 문에 영향을 주지 않기 위해서 이다. # 또한 사용 가능하다.

 

위 사이트에서는 database 버젼 뿐만 아니라 테이블 명도 알아내는 방법이 있으니 위 글을 참고해서 시도해보길 바란다.

다음은 burp suit을 이용해 sql injection 하는 방법을 소개해 보겠다.

+ Recent posts