1 | | - | package burp; |
2 | | - | |
3 | | - | import org.graalvm.compiler.core.common.util.Util; |
4 | | - | |
5 | | - | import java.io.IOException; |
6 | | - | import java.nio.charset.StandardCharsets; |
7 | | - | import java.util.ArrayList; |
8 | | - | import java.util.Arrays; |
9 | | - | |
10 | | - | |
11 | | - | class PayloadInjector { |
12 | | - | |
13 | | - | public IHttpService getService() { |
14 | | - | return service; |
15 | | - | } |
16 | | - | |
17 | | - | private IHttpService service; |
18 | | - | |
19 | | - | public IScannerInsertionPoint getInsertionPoint() { |
20 | | - | return insertionPoint; |
21 | | - | } |
22 | | - | |
23 | | - | private IScannerInsertionPoint insertionPoint; |
24 | | - | |
25 | | - | public IHttpRequestResponse getBase() { |
26 | | - | return base; |
27 | | - | } |
28 | | - | |
29 | | - | private IHttpRequestResponse base; |
30 | | - | |
31 | | - | PayloadInjector(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) { |
32 | | - | this.service = baseRequestResponse.getHttpService(); |
33 | | - | this.base = baseRequestResponse; |
34 | | - | this.insertionPoint = insertionPoint; |
35 | | - | } |
36 | | - | |
37 | | - | // fixme horribly inefficient |
38 | | - | ArrayList<Attack> fuzz(Attack baselineAttack, Probe probe) { |
39 | | - | return fuzz(baselineAttack, probe, null); |
40 | | - | } |
41 | | - | |
42 | | - | ArrayList<Attack> fuzz(Attack baselineAttack, Probe probe, String mutation) { |
43 | | - | ArrayList<Attack> attacks = new ArrayList<>(2); |
44 | | - | Attack breakAttack = buildAttackFromProbe(probe, probe.getNextBreak(), mutation); |
45 | | - | |
46 | | - | if (Utilities.identical(baselineAttack, breakAttack)) { |
47 | | - | return new ArrayList<>(); |
48 | | - | } |
49 | | - | |
50 | | - | for(int k=0; k<probe.getNextEscapeSet().length; k++) { |
51 | | - | Attack doNotBreakAttack = buildAttackFromProbe(probe, probe.getNextEscapeSet()[k], mutation); |
52 | | - | doNotBreakAttack.addAttack(baselineAttack); |
53 | | - | if(!Utilities.identical(doNotBreakAttack, breakAttack)) { |
54 | | - | attacks = verify(doNotBreakAttack, breakAttack, probe, k, mutation); |
55 | | - | if (!attacks.isEmpty()) { |
56 | | - | break; |
57 | | - | } |
58 | | - | } |
59 | | - | } |
60 | | - | |
61 | | - | return attacks; |
62 | | - | } |
63 | | - | |
64 | | - | private ArrayList<Attack> verify(Attack doNotBreakAttackSeed, Attack breakAttackSeed, Probe probe, int chosen_escape, String mutation) { |
65 | | - | ArrayList<Attack> attacks = new ArrayList<>(2); |
66 | | - | Attack mergedBreakAttack = new Attack(); |
67 | | - | mergedBreakAttack.addAttack(breakAttackSeed); |
68 | | - | Attack mergedDoNotBreakAttack = new Attack(); |
69 | | - | mergedDoNotBreakAttack.addAttack(doNotBreakAttackSeed); |
70 | | - | |
71 | | - | Attack tempDoNotBreakAttack = doNotBreakAttackSeed; |
72 | | - | |
73 | | - | for(int i=0; i<Utilities.CONFIRMATIONS; i++) { |
74 | | - | Attack tempBreakAttack = buildAttackFromProbe(probe, probe.getNextBreak(), mutation); |
75 | | - | mergedBreakAttack.addAttack(tempBreakAttack); |
76 | | - | |
77 | | - | if(Utilities.similarIsh(mergedDoNotBreakAttack, mergedBreakAttack, tempDoNotBreakAttack, tempBreakAttack) |
78 | | - | || (probe.getRequireConsistentEvidence() && Utilities.similar(mergedDoNotBreakAttack, tempBreakAttack))) { |
79 | | - | return new ArrayList<>(); |
80 | | - | } |
81 | | - | |
82 | | - | tempDoNotBreakAttack = buildAttackFromProbe(probe, probe.getNextEscapeSet()[chosen_escape], mutation); |
83 | | - | mergedDoNotBreakAttack.addAttack(tempDoNotBreakAttack); |
84 | | - | |
85 | | - | if(Utilities.similarIsh(mergedDoNotBreakAttack, mergedBreakAttack, tempDoNotBreakAttack, tempBreakAttack) |
86 | | - | || (probe.getRequireConsistentEvidence() && Utilities.similar(mergedBreakAttack, tempDoNotBreakAttack))) { |
87 | | - | return new ArrayList<>(); |
88 | | - | } |
89 | | - | |
90 | | - | } |
91 | | - | |
92 | | - | // this final probe pair is sent out of order, to prevent alternation false positives |
93 | | - | tempDoNotBreakAttack = buildAttackFromProbe(probe, probe.getNextEscapeSet()[chosen_escape], mutation); |
94 | | - | mergedDoNotBreakAttack.addAttack(tempDoNotBreakAttack); |
95 | | - | Attack tempBreakAttack = buildAttackFromProbe(probe, probe.getNextBreak(), mutation); |
96 | | - | mergedBreakAttack.addAttack(tempBreakAttack); |
97 | | - | |
98 | | - | // point is to exploit response attributes that vary in "don't break" responses (but are static in 'break' responses) |
99 | | - | if(Utilities.similarIsh(mergedDoNotBreakAttack, mergedBreakAttack, tempDoNotBreakAttack, tempBreakAttack) |
100 | | - | || (probe.getRequireConsistentEvidence() && Utilities.similar(mergedBreakAttack, tempDoNotBreakAttack))) { |
101 | | - | return new ArrayList<>(); |
102 | | - | } |
103 | | - | |
104 | | - | attacks.add(mergedBreakAttack); |
105 | | - | attacks.add(mergedDoNotBreakAttack); |
106 | | - | |
107 | | - | return attacks; |
108 | | - | } |
109 | | - | |
110 | | - | |
111 | | - | private Attack buildAttackFromProbe(Probe probe, String payload, String mutation) { |
112 | | - | boolean randomAnchor = probe.getRandomAnchor(); |
113 | | - | byte prefix = probe.getPrefix(); |
114 | | - | |
115 | | - | String anchor = ""; |
116 | | - | if (randomAnchor) { |
117 | | - | anchor = Utilities.generateCanary(); |
118 | | - | } |
119 | | - | //else { |
120 | | - | // payload = payload.replace("z", Utilities.generateCanary()); |
121 | | - | //} |
122 | | - | |
123 | | - | String base_payload = payload; |
124 | | - | if (prefix == Probe.PREPEND) { |
125 | | - | payload += insertionPoint.getBaseValue(); |
126 | | - | } |
127 | | - | else if (prefix == Probe.APPEND) { |
128 | | - | payload = insertionPoint.getBaseValue() + anchor + payload; |
129 | | - | } |
130 | | - | else if (prefix == Probe.REPLACE) { |
131 | | - | // payload = payload; |
132 | | - | } |
133 | | - | else { |
134 | | - | Utilities.err("Unknown payload position"); |
135 | | - | } |
136 | | - | |
137 | | - | |
138 | | - | IHttpRequestResponse req = buildRequest(payload, probe.useCacheBuster(), mutation); |
139 | | - | if(randomAnchor) { |
140 | | - | req = Utilities.highlightRequestResponse(req, anchor, anchor, insertionPoint); |
141 | | - | } |
142 | | - | |
143 | | - | return new Attack(req, probe, base_payload, anchor); |
144 | | - | } |
145 | | - | |
146 | | - | IHttpRequestResponse buildRequest(String payload, boolean needCacheBuster) { |
147 | | - | return buildRequest(payload, needCacheBuster, null); |
148 | | - | } |
149 | | - | |
150 | | - | IHttpRequestResponse buildRequest(String payload, boolean needCacheBuster, String mutation) { |
151 | | - | |
152 | | - | byte[] request = insertionPoint.buildRequest(payload.getBytes()); |
153 | | - | |
154 | | - | if (needCacheBuster) { |
155 | | - | request = Utilities.addCacheBuster(request, Utilities.generateCanary()); |
156 | | - | } |
157 | | - | |
158 | | - | if (mutation != null) { |
159 | | - | HeaderMutator mutator = new HeaderMutator(); |
160 | | - | try { |
161 | | - | byte[] newRequest = mutator.mutateRequest(request, mutation, payload.split("\\|")); |
162 | | - | request = newRequest; |
163 | | - | } catch (IOException e) { |
164 | | - | Utilities.out(e.toString()); |
165 | | - | } |
166 | | - | } |
167 | | - | |
168 | | - | IHttpRequestResponse requestResponse = burp.Utilities.attemptRequest(service, request); |
169 | | - | //Utilities.out("Payload: "+payload+"|"+baseRequestResponse.getHttpService().getHost()); |
170 | | - | |
171 | | - | return requestResponse;// Utilities.buildRequest(baseRequestResponse, insertionPoint, payload) |
172 | | - | } |
173 | | - | |
174 | | - | Attack probeAttack(String payload) { |
175 | | - | return probeAttack(payload, null); |
176 | | - | } |
177 | | - | |
178 | | - | Attack probeAttack(String payload, String mutation) { |
179 | | - | byte[] request = insertionPoint.buildRequest(payload.getBytes()); |
180 | | - | |
181 | | - | //IParameter cacheBuster = burp.Utilities.helpers.buildParameter(Utilities.generateCanary(), "1", IParameter.PARAM_URL); |
182 | | - | //request = burp.Utilities.helpers.addParameter(request, cacheBuster); |
183 | | - | //request = burp.Utilities.appendToQuery(request, Utilities.generateCanary()+"=1"); |
184 | | - | request = Utilities.addCacheBuster(request, Utilities.generateCanary()); |
185 | | - | |
186 | | - | if (mutation != null) { |
187 | | - | HeaderMutator mutator = new HeaderMutator(); |
188 | | - | try { |
189 | | - | byte[] newRequest = mutator.mutateRequest(request, mutation, payload.split("\\|")); |
190 | | - | request = newRequest; |
191 | | - | } catch (java.io.IOException e) { |
192 | | - | //Utilities.out("ERROR: failed to mutate request: " + e.toString()); |
193 | | - | } |
194 | | - | } |
195 | | - | |
196 | | - | IHttpRequestResponse requestResponse = burp.Utilities.attemptRequest(service, request); |
197 | | - | return new Attack(requestResponse, null, null, ""); |
198 | | - | } |
199 | | - | |
200 | | - | |
201 | | - | Attack buildAttack(String payload, boolean random) { |
202 | | - | String canary = ""; |
203 | | - | if (random) { |
204 | | - | canary = Utilities.generateCanary(); |
205 | | - | } |
206 | | - | |
207 | | - | return new Attack(buildRequest(canary+payload, !random, null), null, null, canary); |
208 | | - | |
209 | | - | } |
210 | | - | |
211 | | - | } |
212 | | - | |