-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhammer.pas
504 lines (465 loc) · 15.2 KB
/
hammer.pas
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
program LoadTester;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, IdHTTP, IdGlobal, IdSSLOpenSSL, IdException, SyncObjs, DateUtils, Math,
StrUtils, JSON;
type
TLoadTestThread = class(TThread)
private
FURL: string;
FMethod: string;
FHeaders: TStringList;
FData: string;
FTimeout: Integer;
FRetries: Integer;
FResponseTime: TDateTime;
FResponseCode: Integer;
FSuccess: Boolean;
FLock: TCriticalSection;
FLog: TextFile;
FResults: TJSONArray;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; const AURL, AMethod: string;
AHeaders: TStringList; AData: string; ATimeout, ARetries: Integer; ALock: TCriticalSection;
ALog: TextFile; AResults: TJSONArray);
destructor Destroy; override;
end;
var
ver_major, ver_minor, patch: Byte;
bots: Integer;
url, method: string;
headers: TStringList;
data: string;
timeout, retries: Integer;
rateLimit: Double;
logFile: TextFile;
lock: TCriticalSection;
responseTimes: array of Double;
responseCodes: array of Integer;
startTime, endTime: TDateTime;
totalRequests, successfulRequests: Integer;
resultsArray: TJSONArray;
portScan: Boolean;
fingerprint: Boolean;
target_ip: string;
start_port, end_port: Integer;
fingerprint_url: string;
procedure TLoadTestThread.Execute;
var
http: TIdHTTP;
proxy: TIdConnectThroughHTTP;
retryCount: Integer;
startTime, endTime: TDateTime;
resultObj: TJSONObject;
begin
FSuccess := False;
retryCount := 0;
while (retryCount <= FRetries) and not Terminated do
begin
http := TIdHTTP.Create(nil);
proxy := TIdConnectThroughHTTP.Create(nil);
try
http.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(http);
http.HandleRedirects := True;
http.MaxAuthRetries := 3;
http.Request.CustomHeaders.Assign(FHeaders);
http.ReadTimeout := FTimeout;
http.ConnectTimeout := FTimeout;
http.IOHandler.ReadTimeout := FTimeout;
http.IOHandler.ConnectTimeout := FTimeout;
if FHeaders.Values['Proxy'] <> '' then
begin
proxy.Host := FHeaders.Values['Proxy'];
proxy.Port := StrToIntDef(FHeaders.Values['ProxyPort'], 8080);
http.IOHandler := proxy;
end;
startTime := Now;
try
case FMethod of
'GET': FResponseCode := http.Get(FURL).ResponseCode;
'POST': FResponseCode := http.Post(FURL, TStringStream.Create(FData)).ResponseCode;
'PUT': FResponseCode := http.Put(FURL, TStringStream.Create(FData)).ResponseCode;
'DELETE': FResponseCode := http.Delete(FURL).ResponseCode;
end;
FSuccess := True;
except
on E: Exception do
begin
FLock.Enter;
try
Writeln(logFile, Format('Error: %s at %s', [E.Message, FormatDateTime('yyyy-mm-dd hh:nn:ss', Now)]));
finally
FLock.Leave;
end;
Inc(retryCount);
end;
end;
endTime := Now;
FResponseTime := MilliSecondsBetween(endTime, startTime) / MSecsPerSec;
FLock.Enter;
try
Writeln(logFile, Format('Response Code: %d, Time: %.3f sec, at %s', [FResponseCode, FResponseTime, FormatDateTime('yyyy-mm-dd hh:nn:ss', Now)]));
SetLength(responseTimes, Length(responseTimes) + 1);
responseTimes[High(responseTimes)] := FResponseTime;
SetLength(responseCodes, Length(responseCodes) + 1);
responseCodes[High(responseCodes)] := FResponseCode;
Inc(totalRequests);
if FSuccess then
Inc(successfulRequests);
resultObj := TJSONObject.Create;
try
resultObj.AddPair('ResponseCode', TJSONNumber.Create(FResponseCode));
resultObj.AddPair('ResponseTime', TJSONNumber.Create(FResponseTime));
FResults.AddElement(resultObj);
except
resultObj.Free;
raise;
end;
finally
FLock.Leave;
end;
finally
http.Free;
proxy.Free;
end;
end;
end;
constructor TLoadTestThread.Create(CreateSuspended: Boolean; const AURL, AMethod: string;
AHeaders: TStringList; AData: string; ATimeout, ARetries: Integer; ALock: TCriticalSection;
ALog: TextFile; AResults: TJSONArray);
begin
inherited Create(CreateSuspended);
FURL := AURL;
FMethod := AMethod;
FHeaders := TStringList.Create;
FHeaders.Assign(AHeaders);
FData := AData;
FTimeout := ATimeout;
FRetries := ARetries;
FLock := ALock;
FLog := ALog;
FResults := AResults;
end;
destructor TLoadTestThread.Destroy;
begin
FHeaders.Free;
inherited Destroy;
end;
procedure ParseCommandLine;
var
i: Integer;
param: string;
begin
portScan := False;
fingerprint := False;
for i := 1 to ParamCount do
begin
param := ParamStr(i);
if param.StartsWith('--') or param.StartsWith('-') then
begin
if param.StartsWith('--url=') or param.StartsWith('-u=') then
url := Copy(param, Pos('=', param) + 1, Length(param))
else if param.StartsWith('--bots=') or param.StartsWith('-b=') then
bots := StrToIntDef(Copy(param, Pos('=', param) + 1, Length(param)), 0)
else if param.StartsWith('--timeout=') or param.StartsWith('-t=') then
timeout := StrToIntDef(Copy(param, Pos('=', param) + 1, Length(param)), 10000)
else if param.StartsWith('--version') or param.StartsWith('-v') then
begin
Writeln(Format('ROSASINESUS v%d.%d.%d', [ver_major, ver_minor, patch]));
Halt;
end
else if param.StartsWith('--help') or param.StartsWith('-h') then
begin
Writeln('Usage:');
Writeln(' ./loadtester --url=<URL> --bots=<bots> [--timeout=<timeout>] [--version] [--help]');
Writeln(' ./loadtester --port-scan --target-ip=<IP> --start-port=<start> --end-port=<end>');
Writeln(' ./loadtester --fingerprint --fingerprint-url=<URL>');
Writeln('Flags:');
Writeln(' --url, -u: The target URL for testing.');
Writeln(' --bots, -b: The number of concurrent bots for the attack.');
Writeln(' --timeout, -t: Timeout for each request in milliseconds (optional, default is 10000 ms).');
Writeln(' --version, -v: Prints the version and exits.');
Writeln(' --help, -h: Prints this usage message.');
Writeln(' --port-scan, -p: Enable port scanning.');
Writeln(' --target-ip, -i: Target IP address for port scanning.');
Writeln(' --start-port, -s: Starting port for scanning.');
Writeln(' --end-port, -e: Ending port for scanning.');
Writeln(' --fingerprint, -f: Enable web server fingerprinting.');
Writeln(' --fingerprint-url, -fu: URL for web server fingerprinting.');
Halt;
end
else if param.StartsWith('--port-scan') or param.StartsWith('-p') then
portScan := True
else if param.StartsWith('--target-ip=') or param.StartsWith('-i=') then
target_ip := Copy(param, Pos('=', param) + 1, Length(param))
else if param.StartsWith('--start-port=') or param.StartsWith('-s=') then
start_port := StrToIntDef(Copy(param, Pos('=', param) + 1, Length(param)), 1)
else if param.StartsWith('--end-port=') or param.StartsWith('-e=') then
end_port := StrToIntDef(Copy(param, Pos('=', param) + 1, Length(param)), 1024)
else if param.StartsWith('--fingerprint') or param.StartsWith('-f') then
fingerprint := True
else if param.StartsWith('--fingerprint-url=') or param.StartsWith('-fu=') then
fingerprint_url := Copy(param, Pos('=', param) + 1, Length(param));
end;
end;
if portScan and fingerprint then
begin
Writeln('Error: --port-scan and --fingerprint cannot be used together.');
Halt;
end;
if portScan then
begin
if target_ip = '' then
begin
Writeln('Error: --target-ip is required for port scanning.');
Halt;
end;
if start_port = 0 then
begin
Writeln('Error: --start-port is required for port scanning.');
Halt;
end;
if end_port = 0 then
begin
Writeln('Error: --end-port is required for port scanning.');
Halt;
end;
end;
if fingerprint then
begin
if fingerprint_url = '' then
begin
Writeln('Error: --fingerprint-url is required for web server fingerprinting.');
Halt;
end;
end;
if not portScan and not fingerprint and (url = '' or bots = 0) then
begin
Writeln('Error: --url and --bots are required for load testing.');
Halt;
end;
end;
procedure display_real_time_metrics;
var
currentRequests, currentSuccessfulRequests: Integer;
currentResponseTime: Double;
begin
while totalRequests < bots do
begin
lock.Enter;
try
currentRequests := totalRequests;
currentSuccessfulRequests := successfulRequests;
if Length(responseTimes) > 0 then
currentResponseTime := responseTimes[High(responseTimes)]
else
currentResponseTime := 0;
finally
lock.Leave;
end;
Writeln(Format('Requests Sent: %d, Successful: %d, Last Response Time: %.3f sec', [currentRequests, currentSuccessfulRequests, currentResponseTime]));
Sleep(1000); // Update every second
end;
end;
procedure simulate_traffic_profile(profile: string; bots: Integer; const url, method: string; headers: TStringList; const data: string;
timeout, retries: Integer; rateLimit: Double; results: TJSONArray);
begin
case LowerCase(profile) of
'spike':
begin
// Simulate a spike in traffic
bots := bots * 10; // Increase bots for spike
run_tests(bots, url, method, headers, data, timeout, retries, rateLimit, results);
bots := bots div 10; // Reset bots to original
end;
'wave':
begin
// Simulate a wave of traffic
for var i := 1 to 5 do
begin
run_tests(bots div 5, url, method, headers, data, timeout, retries, rateLimit, results);
Sleep(2000); // Wait for 2 seconds between waves
end;
end;
'sustained':
begin
// Simulate sustained traffic
run_tests(bots, url, method, headers, data, timeout, retries, rateLimit, results);
end;
else
Writeln('Unknown traffic profile, using sustained traffic by default.');
run_tests(bots, url, method, headers, data, timeout, retries, rateLimit, results);
end;
end;
procedure run_tests(bots: Integer; const url, method: string; headers: TStringList; const data: string;
timeout, retries: Integer; rateLimit: Double; results: TJSONArray);
var
threads: array of TLoadTestThread;
i: Integer;
interval: Double;
begin
interval := 1 / rateLimit;
SetLength(threads, bots);
lock := TCriticalSection.Create;
for i := 0 to bots - 1 do
begin
threads[i] := TLoadTestThread.Create(True, url, method, headers, data, timeout, retries, lock, logFile, results);
threads[i].FreeOnTerminate := True;
threads[i].Resume;
Sleep(Round(interval * 1000)); // Sleep to control rate limit
end;
// Wait for all threads to complete
for i := 0 to bots - 1 do
begin
while threads[i] <> nil do
begin
Sleep(100);
Threads[i].WaitFor;
end;
end;
lock.Free;
end;
procedure log_results(results: TJSONArray);
var
totalResponseTime: Double;
minResponseTime, maxResponseTime, avgResponseTime: Double;
jsonFile: TextFile;
jsonStr: string;
begin
totalResponseTime := 0;
minResponseTime := MaxDouble;
maxResponseTime := 0;
for var responseTime in responseTimes do
begin
totalResponseTime := totalResponseTime + responseTime;
if responseTime < minResponseTime then
minResponseTime := responseTime;
if responseTime > maxResponseTime then
maxResponseTime := responseTime;
end;
if Length(responseTimes) > 0 then
avgResponseTime := totalResponseTime / Length(responseTimes)
else
avgResponseTime := 0;
Writeln(logFile, '------------------- Results -------------------');
Writeln(logFile, Format('Total Requests: %d', [totalRequests]));
Writeln(logFile, Format('Successful Requests: %d', [successfulRequests]));
Writeln(logFile, Format('Average Response Time: %.3f sec', [avgResponseTime]));
Writeln(logFile, Format('Minimum Response Time: %.3f sec', [minResponseTime]));
Writeln(logFile, Format('Maximum Response Time: %.3f sec', [maxResponseTime]));
Writeln(logFile, '-------------------------------------------');
// Save results to JSON file
AssignFile(jsonFile, 'load_test_results.json');
Rewrite(jsonFile);
jsonStr := results.ToString;
Writeln(jsonFile, jsonStr);
CloseFile(jsonFile);
end;
// Function to scan a single port
procedure scan_port(target_ip: string; port: Integer);
var
client: TIdTCPClient;
open: Boolean;
begin
client := TIdTCPClient.Create(nil);
try
client.Host := target_ip;
client.Port := port;
client.ConnectTimeout := 1000; // 1 second timeout
try
client.Connect;
open := True;
except
on E: Exception do
open := False;
end;
if open then
Writeln(Format('Port %d is OPEN', [port]))
else
Writeln(Format('Port %d is CLOSED or FILTERED', [port]));
finally
client.Free;
end;
end;
// Function to scan a range of ports
procedure scan_ports(target_ip: string; start_port, end_port: Integer);
var
port: Integer;
begin
for port := start_port to end_port do
scan_port(target_ip, port);
end;
// Function to fingerprint web server
procedure fingerprint_web_server(url: string);
var
http: TIdHTTP;
response: IIdHTTPResponse;
serverHeader: string;
begin
http := TIdHTTP.Create(nil);
try
http.HandleRedirects := True;
http.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(http);
try
response := http.Head(url);
serverHeader := response.Server;
if serverHeader <> '' then
Writeln(Format('Web Server: %s', [serverHeader]))
else
Writeln('Web Server: Unknown');
except
on E: Exception do
Writeln(Format('Error fingerprinting web server: %s', [E.Message]));
end;
finally
http.Free;
end;
end;
begin
ver_major := 1;
ver_minor := 1;
patch := 0;
Writeln('ROSASINESUS');
Writeln(Format('ver %d.%d.%d', [ver_major, ver_minor, patch]));
Writeln('Load Tester - DDOS Simulator for your own website');
AssignFile(logFile, 'load_test.log');
Rewrite(logFile);
ParseCommandLine;
headers := TStringList.Create;
try
method := 'GET'; // Default method
data := '';
timeout := 10000; // Default timeout in milliseconds
retries := 3; // Default retries
rateLimit := 1.0; // Default rate limit (1 request per second)
if portScan then
begin
Writeln(Format('Scanning %s from port %d to %d...', [target_ip, start_port, end_port]));
scan_ports(target_ip, start_port, end_port);
end
else if fingerprint then
begin
Writeln(Format('Fingerprinting web server at %s...', [fingerprint_url]));
fingerprint_web_server(fingerprint_url);
end
else
begin
startTime := Now;
resultsArray := TJSONArray.Create;
try
display_real_time_metrics;
simulate_traffic_profile('sustained', bots, url, method, headers, data, timeout, retries, rateLimit, resultsArray);
endTime := Now;
log_results(resultsArray);
finally
resultsArray.Free;
end;
Writeln(Format('Test completed in %.3f sec', [MilliSecondsBetween(endTime, startTime) / MSecsPerSec]));
end;
finally
headers.Free;
end;
CloseFile(logFile);
end.