[原创]WEB CTF题目

访问一下网页:

查看一下网页源码,发现可以下载到Lottery.class。反编译得到java源码:
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class Lottery
extends HttpServlet {
private static String a = "/SECRET";
private static String b = "/FLAG";
private static String c = "0011223344556677";
private static byte[] a() {
return Arrays.copyOfRange(Files.readAllBytes(Paths.get(a, new String[0])), 0, 16);
}
private static byte[] b() {
return Files.readAllBytes(Paths.get(b, new String[0]));
}
private static byte[] a(String arrby) {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
arrby = messageDigest.digest(arrby.getBytes("UTF-8"));
return arrby;
}
private static void a(HttpServletResponse object, String string) {
object = object.getWriter();
string = string.replace("\\", "\\\\");
string = string.replace("\"", "\\\"");
object.println("{\"msg\": \"" + string + "\"}");
}
private boolean a(byte by, int n) {
if (by == Lottery.a()[n]) {
return true;
}
return false;
}
private static int b(String string) {
return Integer.parseInt(string);
}
private static String a(byte[] arrby) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < arrby.length; ++i) {
stringBuilder.append(String.format("%02x", Byte.valueOf(arrby[i])));
}
return stringBuilder.toString();
}
private static String a(int n) {
char[] arrc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
SecureRandom secureRandom = new SecureRandom();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 16; ++i) {
int n2 = secureRandom.nextInt(65535) % arrc.length;
stringBuilder.append(arrc[n2]);
}
return stringBuilder.toString();
}
public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
httpServletResponse.setContentType("text/html");
httpServletResponse.setCharacterEncoding("UTF-8");
HttpSession httpSession = httpServletRequest.getSession();
httpServletResponse.getWriter();
httpSession.setAttribute("prefix", (Object)Lottery.a(16));
httpSession = httpServletRequest.getRequestDispatcher("WEB-INF/jsp/index.jsp");
httpSession.forward((ServletRequest)httpServletRequest, (ServletResponse)httpServletResponse);
}
public void doPost(HttpServletRequest arrby, HttpServletResponse httpServletResponse) {
String string;
byte[] arrby2;
Object object;
httpServletResponse.setContentType("application/json");
httpServletResponse.setCharacterEncoding("UTF-8");
arrby2 = arrby.getSession();
httpServletResponse.getWriter();
object = arrby2.getAttribute("prefix");
object = object == null ? Lottery.a(16) : (String)object;
arrby2.setAttribute("prefix", (Object)Lottery.a(16));
arrby2 = new byte[]{0};
String string2 = arrby.getParameter("captcha");
try {
arrby2 = Lottery.a((String)object + string2);
}
catch (NoSuchAlgorithmException v0) {}
object = arrby.getParameter("line");
int n = Integer.parseInt((String)object);
if (n >= 0 && n <= 3) {
string = "333";
} else if (n >= 4 && n <= 7) {
string = "4444";
} else if (n >= 8 && n <= 11) {
string = "55555";
} else if (n >= 12 && n <= 15) {
string = "666666";
} else {
Lottery.a(httpServletResponse, "line error");
return;
}
object = arrby.getParameter("guess");
if (object == null || ((String)object).equals("")) {
Lottery.a(httpServletResponse, "guess not found");
return;
}
byte by = (byte)arrby.getParameter("guess").toCharArray()[0];
if (Lottery.a(arrby2).startsWith(string)) {
int n2 = n;
byte by2 = by;
Object object2 = this;
if (by2 == Lottery.a()[n2]) {
if (n == 15) {
byte[] arrby3;
arrby3 = new byte[]{0};
try {
arrby3 = Lottery.a(arrby.getRemoteAddr() + new String(Lottery.a()));
}
catch (NoSuchAlgorithmException v1) {}
try {
arrby = new SecretKeySpec(arrby3, "AES");
arrby3 = Cipher.getInstance("AES/CBC/PKCS5Padding");
object2 = new IvParameterSpec(c.getBytes("UTF-8"));
arrby3.init(1, (Key)arrby, (AlgorithmParameterSpec)object2);
arrby = arrby3.doFinal(Files.readAllBytes(Paths.get(b, new String[0])));
Lottery.a(httpServletResponse, "encrypted flag is " + Lottery.a(arrby));
}
catch (Exception v2) {
Lottery.a(httpServletResponse, "encryption error");
return;
}
}
Lottery.a(httpServletResponse, "good");
return;
}
Lottery.a(httpServletResponse, "bad luck");
return;
}
Lottery.a(httpServletResponse, "captcha error");
}
public void destroy() {
}
}
研究了半天,写个python脚本爆破一下吧。
import requests
import re
import hashlib as h
def breakCaptcha(prefix, start):
i = 1000000
while True:
digest=h.new('md5', prefix+str(i)).hexdigest()
if digest.startswith(start):
return str(i)
i += 1
def broute(s,n):
for i in range(256):
data=s.get("http://52.196.144.8:8080/").text
prefix=re.findall('(?<=md5\(\s").*?(?=")',data)[0]
captcha=breakCaptcha(prefix, prefixes[n])
data = {'guess':chr(i),'captcha':captcha,'line':n }
resp = s.post('http://52.196.144.8:8080/', data=data).text
if ("good" in resp) or ("flag" in resp):
print 'securet[%d]=%d' %(n,i)
if 'flag' in resp:
print resp
return i
i+=1
s = requests.Session()
captcha=''
prefixes=['333']*4+ ['4444']*5 + ['55555']*6 +['666666']*7
secret=[]
for i in range(16):
secret.append(broute(s,i))
print secret
慢慢的跑吧,最后得到secret的16个字节为:
132 203 41 215 52 248 159 26 20 59 8 177 119 252 43 28
其中跑最后一个字节还会得到flag的加密数据:
securet[15]=28
{"msg": "encrypted flag is 1c96228f368c3b214c3a481653d019ad35782e275e3cf7bde46f1fb7b09ea48abee650a18f75d0eb64b9ebfb52b4062e"}
解密flag必须在题目提示的java环境下操作,否则解密成功不了。
