Ao fazer login, nos deparamos com uma tela de login. Temos a opção de pegar o código fonte da página.
<?php
define("ALPHA", str_split("abcdefghijklmnopqrstuvwxyz0123456789_-"));
ini_set("error_reporting", 0);
if(isset($_GET['source'])) {
highlight_file(__FILE__);
}
include "flag.php"; // $FLAG
$SEEDS = str_split($FLAG, 4);
function session_id_secure($id) {
global $SEEDS;
mt_srand(intval(bin2hex($SEEDS[md5($id)[0] % (count($SEEDS))]),16));
$id = "";
for($i=0;$i<1000;$i++) {
$id .= ALPHA[mt_rand(0,count(ALPHA)-1)];
}
return $id;
}
if(isset($_POST['username']) && isset($_POST['password'])) {
session_id(session_id_secure($_POST['username'] . $_POST['password']));
session_start();
echo "Thank you for signing up!";
}else {
echo "Please provide the necessary data!";
}
?>
Analisando o código, vemos que a flag é dividida em segmentos de 4 bytes. Temos também a função session_id_secure() que recebe o nome de usuário e senha concatenados. Vamos então analisar essa função
function session_id_secure($id) {
global $SEEDS;
mt_srand(intval(bin2hex($SEEDS[md5($id)[0] % (count($SEEDS))]),16));
$id = "";
for($i=0;$i<1000;$i++) {
$id .= ALPHA[mt_rand(0,count(ALPHA)-1)];
}
return $id;
}
Essa função utiliza mt_rand() para gerar números pseudoaleatórios, mas antes disso, inicializa a seed do gerador (mt_srand()) com um valor derivado de $SEEDS. Esse array contém os segmentos da flag e a posição utilizada é determinada pelo primeiro caractere do hash md5($id), tomado como um número hexadecimal (0-9A-F) e reduzido ao intervalo válido pelo operador módulo (% count($SEEDS)).
Após definir a seed, a função gera um identificador de sessão composto por 1000 caracteres aleatórios escolhidos de ALPHA.
O problema é que mt_srand() torna a sequência gerada por mt_rand() completamente previsível. Com ferramentas como php_mt_seed, podemos recuperar a seed utilizada a partir dos valores gerados.
Como o primeiro caractere do hash md5 sempre será um hexadecimal (0-9A-F), há no máximo 16 possíveis índices dentro do array $SEEDS. Isso significa que, ao testar diferentes entradas (username e password), conseguimos inferir qual segmento da flag foi usado como seed e, consequentemente, extrair partes dela.