Or not, back to HOME!




CHAINSAW

SUMMARY

A superuser-owned and SUID-bit-set binary does not specify full path. Such binary resides at a directory owned by user bobby and can be executed by user bobby.

Bobby’s ssh private key is distributed via email by user administrator, and for some reason the email content is stored on the box, in a file viewable by user administrator.

Administrator runs an application which takes input without sanitization from an Ethereum smart contract. Such smart contract seems not subject to access control based on signing, and contains a function that can set the input value, and the visibility of this function is public. The RPC endpoint of this Ethereum network is for some reason available to everyone.



REFERENCE

Solidity - Solidity 0.4.24 documentation
JSON Formatter & Validator
Remix - Ethereum IDE
json-rpc | Ethereum Wiki



WALKTHROUGH

Skip to obtaining foothold!
Skip to lateral movement!
Skip to obtaining root!


Surface check.
nmap -sV -sC chainsaw.htb -oA tcp_t1k -v

Scan result.
Host is up (0.37s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| -rw-r--r--    1 1001     1001        23828 Dec 05  2018 WeaponizedPing.json
| -rw-r--r--    1 1001     1001          243 Dec 12  2018 WeaponizedPing.sol
|_-rw-r--r--    1 1001     1001           44 Jun 28 06:15 address.txt
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 3
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open  ssh     OpenSSH 7.7p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 02:dd:8a:5d:3c:78:d4:41:ff:bb:27:39:c1:a2:4f:eb (RSA)
|   256 3d:71:ff:d7:29:d5:d4:b2:a6:4f:9d:eb:91:1b:70:9f (ECDSA)
|_  256 7e:02:da:db:29:f9:d2:04:63:df:fc:91:fd:a2:5a:f2 (ED25519)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Per nmap, ftp is open on port 21 and ssh is open on port 22. vsftpd 3.0.3 config option anonymous_enable and no_anon_password are set, thus a login with username ftp or anonymous and no password, is allowed. Nmap logs in via such mean and lists three files: WeaponizedPing.json, WeaponizedPing.sol, and address.txt. The last-modified time of address.txt is suspiciously close to now, no idea why.
searchsploit: nothing interesting.
wget ftp://ftp:@chainsaw.htb/* to download the share for a view.


Upon saving files, wget prints that WeaponizedPing.json is 23828 characters long, while WeaponizedPing.sol being 243, that is, almost 100 times of size difference. Decide to check out the smaller one first, as they share the non-extension part of their filenames, should be related somehow.
Content of WeaponizedPing.sol.

pragma solidity ^0.4.24;

contract WeaponizedPing {
  string store = "google.com";

  function getDomain() public view returns (string) {
      return store;
  }

  function setDomain(string _value) public {
      store = _value;
  }
}

A variable (store) whose current value appears to be a domain name (google.com), and two functions, one (getDomain) to call for getting the current value of such variable, and one (setDomain) to call for setting a new value for such variable. This bundle of stuff is named WeaponizedPing, a domain name sure can be the argument supplied to a ping application. but no idea how such application looks like to a point where it can claim to be “weaponized”.


According to this documentation, the solidity ^0.4.24 written in the first line signifies that, the bundle of stuff below that we just talked about, also called a contract, is written in a language called solidity, and is intended to be compiled by Solidity Compiler with version from 0.4.24 up to but not include 0.5.0. Also upon compilation, “a JSON file, the contract metadata, that contains information about the current contract” will be automatically generated.
Examine WeaponizedPing.json under a JSON formatter confirms that sourcePath is the original full path of WeaponizedPing.sol, and source is the content of WeaponizedPing.sol (one variable and two functions which simply get and set the value of this one variable, as we saw earlier) written as one string. The compiler indeed is solc 0.4.24.
The rest is mainly compiled bytecode, info of which part of the bytecode is translated from which part of the source, a huge amount of metadata of the source, namely abi, ast, legacyAST, which account for the almost 100x size difference, and some trivia such as version number of the overall formatting and the last-updated date of this JSON.
The value of key address, which is nested under key networks, initially pops out as interesting, for it looks like the same type of thing found in that address.txt file in the ftp share. But later on the documentation points out that it is the hash and thus used as the identifier of the current contract, in this case, string google.com and its interface. Can it be that the address in that shared address.txt, when queried, points to a string that is not google.com, that is, some secret virtual host of the box, which lead us to some new file share? Or maybe even points to an unrelated contract? Ehh.

Screenshot of content mentioned above.

[source, sourcePath, and compiler.]
[Top-level view when further details are folded in.]
[address, 40-digit hex, just like the one in address.txt.]



At this point, the initial surface check is done. It appears that of all the three files shared via ftp:
WeaponizedPing.sol simply says this string google.com exists, and function setDomain can be called to create a new value and bind variable name store to it;
WeaponizedPing.json is reiterating the content of WeaponizedPing.sol in some super verbose way, the only new stuff is an address, but we already know it points to string google.com and I really can’t see how this address can be used besides to query what value resides at it. Maybe to set a new value, which resides at a new address, the old address need to be supplied as well, so the order of what changing to what can be documented? But even so, the info in this JSON file is last updated at Dec 2018 according to the metadata, unless no new values are set during these years, I can’t see how this WeaponizedPing.json is necessary for anything;
The address in address.txt may point to the newer value of variable store, which would render the address in WeaponizedPing.json useless. This newer value itself might not be interesting, as we’ve guessed earlier, but still its address may be useful to call set on it.


So to sum up, the whole ftp share really just boils down to the syntax setDomain for sure, and maybe the address in address.txt. [And maybe I feel sorry taking you everywhere but only comes to this conclusion.]


And that’s it. How the genuineness of a piece of record is handled, essentially what defines a blockchain, doesn’t quite come into play here. Per my best understanding, such work is done via Ethereum Virtual Machine (EVM), the thing that all thoses compiled bytecodes are for, yet the only surface provided here is language Solidity, which simply uses records, just like every non-blockchain-related language does. So in this case, we can just ignore that this is an Ethereum application instead of a normal one, as such low-level attack surface simply is not exposed to us. Rest assured that all we need to do is normal boring sending strings (syntax setDomain, new value string, and maybe the address in address.txt) in some format to somewhere, phew, and see how the application behaves, aiming for code execution.
No idea in what format and to where should those strings be sent tho. Plan to nmap again but what protocols to even scan for.


Refer to the Solidity 0.4.24 documentation again, “The best way to try out Solidity right now is using Remix”. [The fact that this Remix is a website already says something about the communication protocol, but I for some reason think browsers support a bajillion protocols so I keep searching for network-related information on this website.]

Screenshot of the Remix website.

[Not interested in deploy contracts on our own box, we don’t even have the network setup, so skip the “Compile” tab, land in “Run” tab. The “Account” thing is new, what’s more interesting is that it is also 40-digit hex, just like addresses, could be some hashed encryption key i.e. resolves to an encryption key, hope the key that signed target is zero? Do I have to pay gas? Whoa I sound like an asshole. There is a place for address, but says to load contract, so we don’t even need the WeaponizedPing.sol file, we can just find the endpoint and query it the address in address.txt. Maybe we don’t even need that address, we can just find the endpoint and query it what’s on chain. Huh, now I feel even sorrier taking you everywhere.]
[Not interested in scripting JavaScript in brower console, so skip the “JavaScript VM” option of “Environment”, land in “Web3” stuff, seems to be http or https.]
[Yup. Now we get to type url in the box and button clicking from now on instead of JavaScripting, per my understanding.]
[Side note, find the documentation about json-rpc in Ethereum Wiki.]
[Side note again, one example confirms that I need to be sorry.]
[Another example confirms that address “from” is needed.]

nmap -p- chainsaw.htb -oA tcp_all -v returns port 9810, -sV -sC on this port won’t help much as the Content-Type need to be application/json in the first place.
Time to decide payload to this WeaponizedPing, blackbox with “weaponized” in its name ye just gotta love it.


Decide to keep the google.com string and add some -c 1 so nobody, not even Google, gets flooded. The payload ends up being google.com -c 1; <rev_shell>; ping -c 1 google.com.
[If setDomain looped…maybe this is a fake network. Also my reverse shell code is on chain now, not that it matters but.]
Fill in endpoint url as “Web3 Provider”, “Load contract from Address” with the address in address.txt, supply payload and hit that setDomain button.


And we are user administrator now, and without user flag. [And I’m tired.]
List directory home reveals bobby, we have to be user bobby, check out how user administrator relates to user bobby.
grep -ri bobby /home/administrator

/home/administrator/chainsaw-emp.csv:bobby@chainsaw,Yes,Smart Contract Auditor
Binary file /home/administrator/.ipfs/blocks/SG/CIQBGBBWXJ4N54A5BUNC7WYVUQNXLEQN67SNFTAPGUMYTYB2UAC4SGI.data matches
Binary file /home/administrator/.ipfs/blocks/JL/CIQKWHQP7PFXWUXO6CSIFQMFWW4CTR23WJEFINRLPRC6UAP2ZM5EJLY.data matches
/home/administrator/.ipfs/blocks/OY/CIQG3CRQFZCTNW7GKEFLYX5KSQD4SZUO2SMZHX6ZPT57JIR6WSNTOYQ.data:To: bobbyaxelrod600@protonmail.ch <bobbyaxelrod600@protonmail.ch>
/home/administrator/.ipfs/blocks/OY/CIQG3CRQFZCTNW7GKEFLYX5KSQD4SZUO2SMZHX6ZPT57JIR6WSNTOYQ.data:X-Attached: bobby.key.enc
/home/administrator/.ipfs/blocks/OY/CIQG3CRQFZCTNW7GKEFLYX5KSQD4SZUO2SMZHX6ZPT57JIR6WSNTOYQ.data:X-Original-To: bobbyaxelrod600@protonmail.ch
/home/administrator/.ipfs/blocks/OY/CIQG3CRQFZCTNW7GKEFLYX5KSQD4SZUO2SMZHX6ZPT57JIR6WSNTOYQ.data:Delivered-To: bobbyaxelrod600@protonmail.ch
/home/administrator/.ipfs/blocks/OY/CIQG3CRQFZCTNW7GKEFLYX5KSQD4SZUO2SMZHX6ZPT57JIR6WSNTOYQ.data:Content-Type: application/octet-stream; filename="bobby.key.enc"; name="bobby.key.enc"
/home/administrator/.ipfs/blocks/OY/CIQG3CRQFZCTNW7GKEFLYX5KSQD4SZUO2SMZHX6ZPT57JIR6WSNTOYQ.data:Content-Disposition: attachment; filename="bobby.key.enc"; name="bobby.key.enc"
/home/administrator/.ipfs/blocks/SP/CIQJWFQFWYW5QEXAELBZ5WBEDCJBZ2RSPCHVGDOXQ6FM67VBWKVTSPI.data:bobby@chainsaw,Yes,Java Developer

So Bobby is a “Smart Contract Auditor”, which could be the reason why he is on the box with administrator, also there is one email to Bobby and “Content-Disposition: attachment; filename=bobby.key.enc” seems interesting. Such data is stored in block “CIQG3…NTOYQ” in ipfs, fs could mean file system, fancy files here. The fact that grep can successfully filter out content suggests ipfs command-line interface is not needed to dump the content of the block, afterall what’s shown here above is a file system directory.
cat /home/administrator/.ipfs/blocks/OY/CIQG3...NTOYQ.data

Email content, or web request content, to be more accurate.
X-Pm-Origin: internal
X-Pm-Content-Encryption: end-to-end
Subject: Ubuntu Server Private RSA Key
From: IT Department <chainsaw_admin@protonmail.ch>
Date: Thu, 13 Dec 2018 19:28:54 +0000
Mime-Version: 1.0
Content-Type: multipart/mixed;boundary=---------------------d296272d7cb599bff2a1ddf6d6374d93
To: bobbyaxelrod600@protonmail.ch <bobbyaxelrod600@protonmail.ch>
X-Attached: bobby.key.enc
Message-Id: <zctvLwVo5mWy8NaBt3CLKmxVckb-cX7OCfxUYfHsU2af1NH4krcpgGz7h-PorsytjrT3sA9Ju8WNuWaRAnbE0CY0nIk2WmuwOvOnmRhHPoU=@protonmail.ch>
Received: from mail.protonmail.ch by mail.protonmail.ch; Thu, 13 Dec 2018 14:28:58 -0500
X-Original-To: bobbyaxelrod600@protonmail.ch
Return-Path: <chainsaw_admin@protonmail.ch>
Delivered-To: bobbyaxelrod600@protonmail.ch

-----------------------d296272d7cb599bff2a1ddf6d6374d93
Content-Type: multipart/related;boundary=---------------------ffced83f318ffbd54e80374f045d2451

-----------------------ffced83f318ffbd54e80374f045d2451
Content-Type: text/html;charset=utf-8
Content-Transfer-Encoding: base64

PGRpdj5Cb2JieSw8YnI+PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5JIGFtIHdyaXRpbmcgdGhp
cyBlbWFpbCBpbiByZWZlcmVuY2UgdG8gdGhlIG1ldGhvZCBvbiBob3cgd2UgYWNjZXNzIG91ciBM
aW51eCBzZXJ2ZXIgZnJvbSBub3cgb24uIER1ZSB0byBzZWN1cml0eSByZWFzb25zLCB3ZSBoYXZl
IGRpc2FibGVkIFNTSCBwYXNzd29yZCBhdXRoZW50aWNhdGlvbiBhbmQgaW5zdGVhZCB3ZSB3aWxs
IHVzZSBwcml2YXRlL3B1YmxpYyBrZXkgcGFpcnMgdG8gc2VjdXJlbHkgYW5kIGNvbnZlbmllbnRs
eSBhY2Nlc3MgdGhlIG1hY2hpbmUuPGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+QXR0YWNo
ZWQgeW91IHdpbGwgZmluZCB5b3VyIHBlcnNvbmFsIGVuY3J5cHRlZCBwcml2YXRlIGtleS4gUGxl
YXNlIGFzayZuYnNwO3JlY2VwdGlvbiBkZXNrIGZvciB5b3VyIHBhc3N3b3JkLCB0aGVyZWZvcmUg
YmUgc3VyZSB0byBicmluZyB5b3VyIHZhbGlkIElEIGFzIGFsd2F5cy48YnI+PC9kaXY+PGRpdj48
YnI+PC9kaXY+PGRpdj5TaW5jZXJlbHksPGJyPjwvZGl2PjxkaXY+SVQgQWRtaW5pc3RyYXRpb24g
RGVwYXJ0bWVudDxicj48L2Rpdj4=
-----------------------ffced83f318ffbd54e80374f045d2451--
-----------------------d296272d7cb599bff2a1ddf6d6374d93
Content-Type: application/octet-stream; filename="bobby.key.enc"; name="bobby.key.enc"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="bobby.key.enc"; name="bobby.key.enc"

LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpQcm9jLVR5cGU6IDQsRU5DUllQVEVECkRF
Sy1JbmZvOiBERVMtRURFMy1DQkMsNTNEODgxRjI5OUJBODUwMwoKU2VDTll3L0JzWFB5UXExSFJM
RUVLaGlOSVZmdFphZ3pPY2M2NGZmMUlwSm85SWVHN1ovemordjFkQ0lkZWp1awo3a3RRRmN6VGx0
dG5ySWo2bWRCYjZybk42Q3NQMHZiejlOelJCeWcxbzZjU0dkckwyRW1KTi9lU3hENEFXTGN6Cm4z
MkZQWTBWamxJVnJoNHJqaFJlMndQTm9nQWNpQ0htWkdFQjB0Z3YyL2V5eEU2M1ZjUnpyeEpDWWwr
aHZTWjYKZnZzU1g4QTRRcjdyYmY5Zm56NFBJbUlndXJGM1ZoUW1kbEVtekRSVDRtL3BxZjNUbUdB
azkrd3JpcW5rT0RGUQpJKzJJMWNQYjhKUmhMU3ozcHlCM1gvdUdPVG5ZcDRhRXErQVFaMnZFSnoz
RmZYOVNYOWs3ZGQ2S2FadFNBenFpCnc5ODFFUzg1RGs5TlVvOHVMeG5aQXczc0Y3UHo0RXVKMEhw
bzFlWmdZdEt6dkRLcnJ3OHVvNFJDYWR4N0tIUlQKaW5LWGR1SHpuR0ExUVJPelpXN3hFM0hFTDN2
eFI5Z01WOGdKUkhEWkRNSTl4bHc5OVFWd2N4UGNGYTMxQXpWMgp5cDNxN3lsOTU0U0NNT3RpNFJD
M1o0eVVUakRrSGRIUW9FY0dpZUZPV1UraTFvaWo0Y3J4MUxiTzJMdDhuSEs2CkcxQ2NxN2lPb240
UnNUUmxWcnY4bGlJR3J4bmhPWTI5NWU5ZHJsN0JYUHBKcmJ3c284eHhIbFQzMzMzWVU5ZGoKaFFM
TnA1KzJINCtpNm1tVTN0Mm9nVG9QNHNrVmNvcURsQ0MrajZoRE9sNGJwRDl0NlRJSnVyV3htcEdn
TnhlcwpxOE5zQWVudGJzRCt4bDRXNnE1bXVMSlFtai94UXJySGFjRVpER0k4a1d2WkUxaUZtVmtE
L3hCUm53b0daNWh0CkR5aWxMUHBsOVIrRGg3YnkzbFBtOGtmOHRRbkhzcXBSSGNleUJGRnBucTBB
VWRFS2ttMUxSTUxBUFlJTGJsS0cKandyQ3FSdkJLUk1JbDZ0SmlEODdOTTZKQm9ReWRPRWNwbis2
RFUrMkFjdGVqYnVyMGFNNzRJeWVlbnJHS1NTWgpJWk1zZDJrVFNHVXh5OW8veFBLRGtVdy9TRlV5
U21td2lxaUZMNlBhRGd4V1F3SHh0eHZtSE1oTDZjaXROZEl3ClRjT1RTSmN6bVIycEp4a29oTHJI
N1lyUzJhbEtzTTBGcEZ3bWR6MS9YRFNGMkQ3aWJmL1cxbUF4TDVVbUVxTzAKaFVJdVcxZFJGd0hq
TnZhb1NrK2ZyQXA2aWM2SVBZU21kbzhHWVl5OHBYdmNxd2ZScHhZbEFDWnU0RmlpNmhZaQo0V3Bo
VDNaRllEcnc3U3RnSzA0a2JEN1FrUGVOcTlFdjFJbjJuVmR6RkhQSWg2eitmbXBiZ2ZXZ2VsTEhj
MmV0ClNKWTQrNUNFYmtBY1lFVW5QV1k5U1BPSjdxZVU3K2IvZXF6aEtia3BuYmxtaUsxZjNyZU9N
MllVS3k4YWFsZWgKbkpZbWttcjN0M3FHUnpoQUVUY2tjOEhMRTExZEdFK2w0YmE2V0JOdTE1R29F
V0Fzenp0TXVJVjFlbW50OTdvTQpJbW5mb250T1lkd0I2LzJvQ3V5SlRpZjhWdy9XdFdxWk5icGV5
OTcwNGE5bWFwLytiRHFlUVE0MStCOEFDRGJLCldvdnNneVdpL1VwaU1UNm02clgrRlA1RDVFOHpy
WXRubm1xSW83dnhIcXRCV1V4amFoQ2RuQnJrWUZ6bDZLV1IKZ0Z6eDNlVGF0bFpXeXI0a3N2Rm10
b2JZa1pWQVFQQUJXeitnSHB1S2xycWhDOUFOenIvSm4rNVpmRzAybW9GLwplZEwxYnA5SFBSSTQ3
RHl2THd6VDEvNUw5Wno2WSsxTXplbmRUaTNLcnpRL1ljZnI1WUFSdll5TUxiTGpNRXRQClV2SmlZ
NDB1Mm5tVmI2UXFwaXkyenIvYU1saHB1cFpQay94dDhvS2hLQytsOW1nT1RzQVhZakNiVG1MWHpW
clgKMTVVMjEwQmR4RUZVRGNpeE5pd1Rwb0JTNk1meENPWndOLzFadjBtRThFQ0krNDRMY3FWdDN3
PT0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0=
-----------------------d296272d7cb599bff2a1ddf6d6374d93--

[Is this a joke on protonmail lol.]

The text part of the email states that ssh password auth is disabled, the attachment is encrypted ssh private key and one should physically show up at reception desk to claim the encryption password. Weird priority.
The encryption password is in rockyou.txt: jackychain.
We are user bobby now.


As a “Smart Contract Auditor”, Bobby has on the box a smart contract project called “ChainsawClub”, the layout of the project directory looks similar to that in the ftp share: ChainsawClub.json, ChainsawClub.sol, but this time we have the application binary ChainsawClub, and it for some reason is owned by root and with SUID bit set. Reverse engineer it to see what it does with contract data.
strings /home/bobby/projects/ChainsawClub

sudo -i -u root /root/ChainsawClub/dist/ChainsawClub/ChainsawClub

sudo without full path and we owns the current path which means we get to decide the future path.


cat /root/root.txt

Mine deeper to get rewarded with root coin (RTC)...

Root flag is defined as that hash thing under the name /root/root.txt isn’t it. Some searching points to command debugfs, according to its helping page, cat means “dump an inode out to stdout”, as seen earlier cat doesn’t include the hash, so per debugfs terminology, we need to “dump” something bigger than an “inode”, and “block” seems to be the only candidate here.

debugfs:  blocks /root/root.txt
2655304 
debugfs:  block_dump 2655304
0000  4d69 6e65 2064 6565 7065 7220 746f 2067  Mine deeper to g
0020  6574 2072 6577 6172 6465 6420 7769 7468  et rewarded with
0040  2072 6f6f 7420 636f 696e 2028 5254 4329   root coin (RTC)
0060  2e2e 2e0a 3638 6338 3734 6237 6465 6361  ....68c874b7deca
0100  3162 3964 6433 3836 6364 3463 3339 3562  1b9dd386cd4c395b
0120  3036 6533 0a00 0000 0000 0000 0000 0000  06e3............
0140  0000 0000 0000 0000 0000 0000 0000 0000  ................
*



That’s it for the box.