├── .gitignore ├── README.assets ├── image-20220116100055765.png └── image-20220116101431188.png ├── README.md ├── img ├── origin.png └── u2cTab.png ├── pom.xml └── src ├── U2C ├── CharSetHelper.java └── U2CTab.java └── burp └── BurpExtender.java /.gitignore: -------------------------------------------------------------------------------- 1 | /*.class 2 | /burp/*.class 3 | /U2C/*.class 4 | .project 5 | .classpath 6 | /target/ 7 | *.class 8 | *.prefs 9 | .fatjar 10 | -------------------------------------------------------------------------------- /README.assets/image-20220116100055765.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/README.assets/image-20220116100055765.png -------------------------------------------------------------------------------- /README.assets/image-20220116101431188.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/README.assets/image-20220116101431188.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ################################################### 4 | 5 | 6 | 7 | 8 | 9 | # 该项目不再维护,功能已经合并到[knife](https://github.com/bit4woo/knife) 10 | 11 | 12 | 13 | 14 | 15 | ######################################################### 16 | 17 | ## U2C = Unicode To Chinese 18 | 19 | 20 | A burpsuite Extender That Convert Unicode To Chinese 21 | 22 | Unicode 转中文 的burp suite插件 23 | 24 | GitHub: https://github.com/bit4woo/u2c 25 | 26 | Download: https://github.com/bit4woo/u2c/releases 27 | 28 | ### version 0.1-0.5 29 | 30 | 前五个版本使用自定义的图形界面,是在原始请求响应的基础上修改数据包,然后进行展示。 31 | 32 | 这样有个坏处就是可能破坏响应包在浏览器等终端的展示,可能出现乱码。虽然设计了图像界面进行控制,但是也不够灵活简洁。 33 | 34 | 前五个版本算是走了冤枉路,但也是由于有前五个版本,才有了下面的第六版。 35 | 36 | ### version 0.6 37 | 38 | 完全重写,使用新的tab来展示转码后的响应数据包,不影响原始的响应数据包,更加简洁实用! 39 | 40 | 值得注意的是:U2C中的显示情况与burp中User options---Display--- HTTP Message Display & Character Sets有关,目前burp的API无法完全控制。只能自行设置。 41 | 42 | ![origin](img/origin.png) 43 | 44 | 45 | 46 | ![u2cTab](img/u2cTab.png) 47 | 48 | ### version 0.9 49 | 50 | 将【Unicode转中文】+【切换中文显示的编码】融合。 51 | 52 | ![image-20220116100055765](README.assets/image-20220116100055765.png) 53 | 54 | 55 | 56 | ![image-20220116101431188](README.assets/image-20220116101431188.png) 57 | 58 | 59 | 60 | ### Unicode测试URL 61 | 62 | https://passport.baidu.com/v2/api/getqrcode 63 | 64 | https://aiqicha.baidu.com/index/getCPlaceAjax -------------------------------------------------------------------------------- /img/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/img/origin.png -------------------------------------------------------------------------------- /img/u2cTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/img/u2cTab.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | com.bit4woo.burp 6 | u2c 7 | 0.9 8 | 9 | src 10 | 11 | 12 | maven-compiler-plugin 13 | 3.7.0 14 | 15 | 1.8 16 | 1.8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | maven-assembly-plugin 23 | 3.1.0 24 | 25 | 26 | jar-with-dependencies 27 | 28 | 29 | 30 | 31 | true 32 | 33 | 34 | 35 | 36 | 37 | 38 | make-assembly 39 | package 40 | 41 | single 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | net.portswigger.burp.extender 52 | burp-extender-api 53 | [1.7.22,) 54 | 55 | 56 | 57 | 58 | com.github.bit4woo 59 | burp-api-common 60 | [0.1.3,) 61 | 62 | 63 | 64 | 65 | com.ibm.icu 66 | icu4j 67 | [70.1,) 68 | 69 | 70 | 71 | 72 | org.apache.commons 73 | commons-text 74 | [1.6,) 75 | 76 | 77 | 78 | 79 | com.google.code.gson 80 | gson 81 | [2.3.1,) 82 | 83 | 84 | 85 | 86 | org.beanshell 87 | bsh 88 | [2.0b5,) 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/U2C/CharSetHelper.java: -------------------------------------------------------------------------------- 1 | package U2C; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.nio.charset.Charset; 5 | 6 | import com.ibm.icu.text.CharsetDetector; 7 | import com.ibm.icu.text.CharsetMatch; 8 | 9 | import burp.BurpExtender; 10 | import burp.Getter; 11 | import burp.IExtensionHelpers; 12 | 13 | public class CharSetHelper { 14 | 15 | public static String getSystemCharSet() { 16 | return Charset.defaultCharset().toString(); 17 | } 18 | 19 | /** 20 | * 进行响应包的编码转换。 21 | * @param response 22 | * @return 转换后的格式的byte[] 23 | */ 24 | public static byte[] covertCharSet(byte[] response,String originalCharset,String newCharset) { 25 | if (originalCharset == null) { 26 | return response; 27 | }else { 28 | byte[] newResponse; 29 | try { 30 | newResponse = new String(response,originalCharset).getBytes(newCharset); 31 | return newResponse; 32 | } catch (UnsupportedEncodingException e) { 33 | e.printStackTrace(BurpExtender.getStderr()); 34 | return response; 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * utf8 utf-8都是可以的。 41 | * @param requestOrResponse 42 | * @return 43 | */ 44 | public static String detectCharset(byte[] requestOrResponse){ 45 | IExtensionHelpers helpers = BurpExtender.getCallbacks().getHelpers(); 46 | Getter getter = new Getter(helpers); 47 | boolean isRequest = true; 48 | if (new String(requestOrResponse).startsWith("HTTP/")) {//response 49 | isRequest = false; 50 | } 51 | 52 | String contentType = getter.getHeaderValueOf(isRequest,requestOrResponse,"Content-Type"); 53 | 54 | //1、尝试从contentTpye中获取 55 | if (contentType != null){ 56 | if (contentType.toLowerCase().contains("charset=")) { 57 | String tmpcharSet = contentType.toLowerCase().split("charset=")[1]; 58 | if (tmpcharSet != null && tmpcharSet.length() >0) { 59 | return tmpcharSet; 60 | } 61 | } 62 | } 63 | 64 | //2、尝试使用ICU4J进行编码的检测 65 | CharsetDetector detector = new CharsetDetector(); 66 | detector.setText(requestOrResponse); 67 | CharsetMatch cm = detector.detect(); 68 | if (cm != null) { 69 | return cm.getName(); 70 | } 71 | 72 | //3、http post的默认编码 73 | return "ISO-8859-1"; 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/U2C/U2CTab.java: -------------------------------------------------------------------------------- 1 | package U2C; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Component; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | import java.io.UnsupportedEncodingException; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | import javax.swing.JButton; 14 | import javax.swing.JPanel; 15 | import javax.swing.border.EmptyBorder; 16 | 17 | import org.apache.commons.text.StringEscapeUtils; 18 | 19 | import com.google.gson.Gson; 20 | import com.google.gson.GsonBuilder; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonParser; 23 | 24 | import burp.Getter; 25 | import burp.IBurpExtenderCallbacks; 26 | import burp.IExtensionHelpers; 27 | import burp.IMessageEditorController; 28 | import burp.IMessageEditorTab; 29 | import burp.IRequestInfo; 30 | import burp.IResponseInfo; 31 | import burp.ITextEditor; 32 | 33 | /** 34 | * @author bit4woo 35 | * @github https://github.com/bit4woo 36 | * @version CreateTime:2022年1月15日 下午11:07:59 37 | * 38 | * 想要正确显示中文内容,有三个编码设置会影响结果: 39 | * 1、原始编码,通过代码尝试自动获取,但是结果可能不准确,极端情况下需要手动设置。 40 | * 2、转换后的编码,手动设置。 41 | * 3、burp设置的显示编码,显示时时用的编码,应该和转换后的编码一致。 42 | * 43 | * 原始数据是byte[],但也是文本内容的某种编码的byte[]. 44 | * 45 | */ 46 | public class U2CTab implements IMessageEditorTab{ 47 | private ITextEditor txtInput; 48 | private JPanel panel; 49 | private JButton btnNewButton; 50 | 51 | private byte[] originContent; 52 | private byte[] displayContent = "Nothing to show".getBytes(); 53 | 54 | private List allPossibleCharset; 55 | private int charSetIndex = 0; 56 | 57 | private static IExtensionHelpers helpers; 58 | 59 | public U2CTab(IMessageEditorController controller, boolean editable, IExtensionHelpers helpers, IBurpExtenderCallbacks callbacks) 60 | { 61 | txtInput = callbacks.createTextEditor(); 62 | panel = createpanel(); 63 | txtInput.setEditable(editable); 64 | U2CTab.helpers = helpers; 65 | } 66 | 67 | public String getCurrentCharSet() { 68 | return allPossibleCharset.get(charSetIndex); 69 | } 70 | 71 | public String getNextCharSet() { 72 | if (charSetIndex < allPossibleCharset.size()-1) { 73 | charSetIndex++; 74 | }else { 75 | charSetIndex =0; 76 | } 77 | return allPossibleCharset.get(charSetIndex); 78 | } 79 | 80 | public JPanel createpanel() { 81 | 82 | JPanel contentPane = new JPanel(); 83 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 84 | contentPane.setLayout(new BorderLayout(0, 0)); 85 | 86 | btnNewButton = new JButton("Change Encoding"); 87 | contentPane.add(btnNewButton, BorderLayout.NORTH); 88 | contentPane.add(txtInput.getComponent(), BorderLayout.CENTER); 89 | 90 | btnNewButton.addActionListener(new ActionListener() { 91 | public void actionPerformed(ActionEvent e) { 92 | getNextCharSet(); 93 | display(); 94 | } 95 | }); 96 | 97 | return contentPane; 98 | } 99 | 100 | @Override 101 | public String getTabCaption() 102 | { 103 | return "U2C"; 104 | } 105 | 106 | @Override 107 | public Component getUiComponent() 108 | { 109 | return panel; 110 | } 111 | 112 | @Override 113 | public boolean isEnabled(byte[] content, boolean isRequest) 114 | { 115 | return true; 116 | } 117 | 118 | @Override 119 | public void setMessage(byte[] content, boolean isRequest) 120 | { 121 | String coding = "GBK,GB2312,UTF-8,GB18030,Big5,Big5-HKSCS,UNICODE"; 122 | coding = CharSetHelper.detectCharset(content)+","+coding;//检测到的编码+一些常用编码! 123 | allPossibleCharset = Arrays.asList(coding.split(",")); 124 | 125 | if(content==null) { 126 | txtInput.setText(displayContent); 127 | return; 128 | }else { 129 | originContent = content;//存储原始数据 130 | displayContent = preHandle(content,isRequest,getCurrentCharSet()); 131 | display(); 132 | } 133 | } 134 | 135 | /** 136 | * 使用特定编码显示内容,变化原始编码。 137 | * @param currentCharSet 138 | */ 139 | public void display() { 140 | try { 141 | displayContent = CharSetHelper.covertCharSet(displayContent,getCurrentCharSet(),CharSetHelper.getSystemCharSet()); 142 | txtInput.setText(displayContent); 143 | 144 | String text = String.format("Change Encoding: (Using %s)", getCurrentCharSet()); 145 | btnNewButton.setText(text); 146 | } catch (Exception e) { 147 | e.printStackTrace(); 148 | } 149 | } 150 | 151 | /** 152 | * 中文下的编辑还是有问题,暂不支持。 153 | * 始终返回原始内容。 154 | */ 155 | @Override 156 | public byte[] getMessage() 157 | { 158 | /* 159 | try { 160 | byte[] text = txtInput.getText();//这个时候应该是当前编码对应的byte[] 161 | byte[] result = new String(text,currentCharSet).getBytes(originalCharSet); 162 | return result; 163 | } catch (UnsupportedEncodingException e) { 164 | e.printStackTrace(); 165 | return originContent; 166 | }*/ 167 | return originContent; 168 | } 169 | 170 | @Override 171 | public boolean isModified() 172 | { 173 | return false; 174 | //return txtInput.isTextModified(); 175 | } 176 | 177 | @Override 178 | public byte[] getSelectedData() 179 | { 180 | return txtInput.getSelectedText(); 181 | } 182 | 183 | public static boolean needtoconvert(String str) { 184 | Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))"); 185 | Matcher matcher = pattern.matcher(str.toLowerCase()); 186 | 187 | if (matcher.find() ){ 188 | return true; 189 | }else { 190 | return false; 191 | } 192 | } 193 | 194 | public static boolean isJSON(byte[] content,boolean isRequest) { 195 | if (isRequest) { 196 | IRequestInfo requestInfo = helpers.analyzeRequest(content); 197 | return requestInfo.getContentType() == IRequestInfo.CONTENT_TYPE_JSON; 198 | } else { 199 | IResponseInfo responseInfo = helpers.analyzeResponse(content); 200 | return responseInfo.getInferredMimeType().equals("JSON"); 201 | } 202 | } 203 | 204 | /** 205 | * JSON美化,会自动转换Unicode 206 | * @param inputJson 207 | * @return 208 | */ 209 | public static String beauty(String inputJson) { 210 | //Take the input, determine request/response, parse as json, then print prettily. 211 | Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls().create(); 212 | JsonParser jp = new JsonParser(); 213 | JsonElement je = jp.parse(inputJson); 214 | return gson.toJson(je); 215 | } 216 | 217 | /** 218 | * 如果有Unicode编码的内容,就进行escape操作,否则内容和原始内容一致。 219 | * @param content 220 | * @param isRequest 221 | * @return 222 | */ 223 | public static byte[] preHandle(byte[] content,boolean isRequest,String originalCharSet) { 224 | 225 | byte[] displayContent = content; 226 | 227 | try { 228 | String contentStr = new String(content,originalCharSet); 229 | if (needtoconvert(contentStr)){ 230 | //先尝试进行JSON格式的美化,如果其中有Unicode编码也会自动完成转换 231 | if (isJSON(content, isRequest)) { 232 | try { 233 | Getter getter = new Getter(helpers); 234 | byte[] body = getter.getBody(isRequest, content); 235 | List headers = getter.getHeaderList(isRequest, content); 236 | 237 | byte[] newBody = beauty(new String(body,originalCharSet)).getBytes(originalCharSet); 238 | 239 | displayContent = helpers.buildHttpMessage(headers,newBody); 240 | return displayContent;//如果JSON美化成功,主动返回。 241 | }catch(Exception e) { 242 | 243 | } 244 | } 245 | 246 | int i=0; 247 | do { 248 | contentStr = StringEscapeUtils.unescapeJava(contentStr); 249 | i++; 250 | }while(needtoconvert(contentStr) && i<3); 251 | 252 | displayContent = contentStr.getBytes(originalCharSet); 253 | } 254 | } catch (UnsupportedEncodingException e1) { 255 | 256 | } 257 | return displayContent; 258 | } 259 | 260 | public static void main(String[] args) { 261 | String aaa = "STK_7411642209636022({\"errno\":1003,\"errmsg\":\"\\u7528\\u6237\\u672a\\u767b\\u5f55\",\"errmsg_lang\":{\"zh\":\"\\u7528\\u6237\\u672a\\u767b\\u5f55\",\"en\":\"User is not logged in.\",\"zh-HK\":\"\\u7528\\u6236\\u672a\\u767b\\u9304\"},\"data\":null});"; 262 | System.out.println(StringEscapeUtils.unescapeJava(aaa)); 263 | } 264 | } -------------------------------------------------------------------------------- /src/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.io.PrintWriter; 4 | 5 | import U2C.U2CTab; 6 | 7 | public class BurpExtender implements IBurpExtender,IMessageEditorTabFactory 8 | { 9 | private static IBurpExtenderCallbacks callbacks; 10 | private IExtensionHelpers helpers; 11 | 12 | public static String Version = bsh.This.class.getPackage().getImplementationVersion(); 13 | private static PrintWriter stdout; 14 | private static PrintWriter stderr; 15 | public static String ExtensionName = "U2C"; 16 | public static String Author = "by bit4woo"; 17 | public String github = "https://github.com/bit4woo/U2C"; 18 | 19 | @Override 20 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) 21 | { 22 | BurpExtender.callbacks = callbacks; 23 | callbacks.printOutput(getFullExtensionName()); 24 | callbacks.printOutput(github); 25 | helpers = callbacks.getHelpers(); 26 | callbacks.setExtensionName(getFullExtensionName()); 27 | callbacks.registerMessageEditorTabFactory(this); 28 | } 29 | 30 | @Override 31 | public IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable) { 32 | return new U2CTab(controller, false, helpers, callbacks); 33 | } 34 | 35 | private static void flushStd(){ 36 | try{ 37 | stdout = new PrintWriter(callbacks.getStdout(), true); 38 | stderr = new PrintWriter(callbacks.getStderr(), true); 39 | }catch (Exception e){ 40 | stdout = new PrintWriter(System.out, true); 41 | stderr = new PrintWriter(System.out, true); 42 | } 43 | } 44 | 45 | public static PrintWriter getStdout() { 46 | flushStd();//不同的时候调用这个参数,可能得到不同的值 47 | return stdout; 48 | } 49 | 50 | public static PrintWriter getStderr() { 51 | flushStd(); 52 | return stderr; 53 | } 54 | 55 | //name+version+author 56 | public static String getFullExtensionName(){ 57 | return ExtensionName+" "+Version+" "+Author; 58 | } 59 | 60 | public static IBurpExtenderCallbacks getCallbacks() { 61 | return callbacks; 62 | } 63 | } --------------------------------------------------------------------------------