Tags: http
Rating:
When we connect to the server, we are greeted by a superb ASCII-art captcha :
```
_____ ___
|____ | / | ______
/ / __ __ / /| | |______|
\ \ \ \/ / / /_| | ______
.___/ / > < \___ | |______|
\____/ /_/\_\ |_/
>
```
Yep, no way my browser can handle that : as the problem description states,
we're going to have to write HTTP requests by hand.
### Writing HTTP requests
Mozilla has a pretty good guide to get started on the protocol :
"[An overview of HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview)".
An HTTP request has the following content:
```
{METHOD} {PATH} {PROTOCOL_VERSION}
{HEADERS}
{BODY}
```
The headers and the body are separated by a newline, the body being optional.
Here's a basic example `GET` request :
```
GET /index.html HTTP 1.1
```
And here's an example `POST` request :
```
POST /login.php HTTP 1.1
Content-Length: 30
username=iodbh&password=secret
```
The `Content-Length` header is mandatory if the request has a body, as it tells
the server how many bytes are part of the body. (So in the example above, if I
passed a `Content-Length` of 30, the server would read
`username=iodbh&password=secre` - missing the last byte/character).
So let's try getting the root page :
**Request:**
```
GET / HTTP 1.1
```
**Response:**
```
HTTP/1.1 400 Missing Host header
Date: Mon, 15 Oct 2018 14:00:08 GMT
Connection: keep-alive
Transfer-Encoding: chunked
0
```
Hmmm, looks like the `Host` header is missing.
### The Host header
As you probably know, the DNS protocol helps us resolve hostnames to IP
addresses. But if several domains are hosted on the same machine (or, like
in this problem, behind the same proxy), how does the server know what resource
to return ? It reads the host header.
_Note : This has very interesting security implications, I highly recommend the talk
"[cracking the lens : Targeting HTTP's Hidden Attack-Surface](https://www.youtube.com/watch?v=zP4b3pw94s0)"
([text version](https://portswigger.net/blog/cracking-the-lens-targeting-https-hidden-attack-surface))
by James Kettle on the subject._
The host we want is given in the task description : `flag.local`. So let's
try with the header :
**Request:**
```
GET / HTTP 1.1
Host: flag.local
```
**Response:**
```
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 321
etag: W/"141-LuTf9ny9p1l454tuA3Un+gDFLWo"
date: Mon, 15 Oct 2018 14:21:53 GMT
connection: close
```
```html
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css" />
</head>
<body>
<header>
<h1>Real Business Internal Flag Server</h1>
Login
</header>
<main>
You need to log in before you can see today's flag.
This time we have some HTML back, with a link to `/login`.
### Handling forms
If we follow the link, we get a form :
**Request:**
```
GET /login HTTP 1.1
Host: flag.local
```
**Response:**
```
GET /login HTTP 1.1
Host: flag.local
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 498
etag: W/"1f2-UE5AGAqbLVQn1qrfKFRIqanxl9I"
date: Mon, 15 Oct 2018 14:26:34 GMT
connection: close
```
```html
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css" />
</head>
<body>
<header>
<h1>Real Business Internal Flag Server</h1>
Login
</header>
<main>
<h2>Log In</h2>
<form method="POST" action="login">
<input type="text" name="user" placeholder="Username" />
<input type="password" name="pass" placeholder="Password" />
<input type="submit" />
</form>
</main>
</body>
</html>
```
There are several things to look for here :
- the `method` attribute on the `form` tag : it tells us what methode to use. Here, it's `POST`.
- the `action` attribute on the `form` tag : it tells us what path we should send the data to. Here, it's `login`.
- the `name` attributes on `input` tags. They tell us what fields we're supposed to send. Here, it's `user` and `pass`.
With that and the credentials provided in the task we can construct the next
request. Don't forget the `Content-Length` header since our request has a body !
We also need a [`Content-Type` header](https://en.wikipedia.org/wiki/Media_type) indicating what format the body is in.
Here, it's `application/x-www-form-urlencoded`.
**Request:**
```
POST /login HTTP 1.1
Host: flag.local
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
user=realbusinessuser&pass=potoooooooo
```
**Response:**
```
HTTP/1.1 302 Found
x-powered-by: Express
set-cookie: real_business_token=PHNjcmlwdD5hbGVydCgid2F0Iik8L3NjcmlwdD4%3D; Path=/
location: /
vary: Accept
content-type: text/plain; charset=utf-8
content-length: 23
date: Mon, 15 Oct 2018 14:44:27 GMT
connection: close
Found. Redirecting to /
```
Great, we successfully logged in !
### Managing cookies
So, we got a redirect response to `/`. If we were using a browser, it would
automatically follow the redirect and take us to `/`. So we have to do that by
hand. But it's not the only thing the browser would by doing for us.
HTTP is a stateless protocol, meaning the server is not keeping any state
between the requests at the protocol level - if we just requested `/`, there
would be no trace of our previous login.
The state is instead referenced to by a cookie. We can see it in the previous
response's `Set-Cookie` header. Our browser would automatically save that
cookie, and automatically send it in the request when the host and path match
those of the cookie.
So the last thing we need to do is request `/` again, this time with the cookie.
How do we attach a cookie ? Just use the `Cookie` header :
**Request:**
```
GET / HTTP 1.1
Host: flag.local
Cookie: real_business_token=PHNjcmlwdD5hbGVydCgid2F0Iik8L3NjcmlwdD4%3D
```
**Response: **
```
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 438
etag: W/"1b6-eYJ8DUTdkgByyfWFi6OJJSjopFg"
date: Mon, 15 Oct 2018 15:02:11 GMT
connection: close
```
```html
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css" />
</head>
<body>
<header>
<h1>Real Business Internal Flag Server</h1>
<div class="user">Real Business Employee</div>
Logout
</header>
<main>
Hello Real Business Employee! Today's flag is: picoCTF{0nLY_Us3_n0N_GmO_xF3r_pR0tOcol5_2e14}
.
And our flag is in the response : `picoCTF{0nLY_Us3_n0N_GmO_xF3r_pR0tOcol5_2e14}`