Skip to content

Commit a79c637

Browse files
author
Connor MacLeod
committed
first
0 parents  commit a79c637

File tree

9 files changed

+181
-0
lines changed

9 files changed

+181
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.exe
2+
nimcache/
3+
nimblecache/
4+
htmldocs/

HellShell.nimble

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Package
2+
3+
version = "0.1.0"
4+
author = "0xC130D"
5+
description = "A Nim adaptation of HellShell from MalDev Academy"
6+
license = "GPL-2.0-or-later"
7+
srcDir = "src"
8+
installExt = @["nim"]
9+
bin = @["HellShell"]
10+
11+
12+
# Dependencies
13+
14+
requires "nim >= 2.0.0"
15+
requires "cligen >= 1.6.16"

src/HellShell.nim

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import HellShellpkg / [ ioutils, obfuscation ]
2+
import std/strutils
3+
4+
type
5+
Operations = enum
6+
UUID = "uuid",
7+
IPv4 = "ipv4",
8+
IPv6 = "ipv6",
9+
MAC = "mac"
10+
11+
12+
when isMainModule:
13+
proc argParser(obfuscation: Operations, filename: string, outfile:string = "stdout") =
14+
var
15+
shellcode: seq[uint8] = filename.readFileToBytes()
16+
obfuscated: seq[string]
17+
case obfuscation:
18+
of UUID:
19+
obfuscated = shellcode.toUUIDs
20+
of IPv4:
21+
obfuscated = shellcode.toIPv4
22+
of IPv6:
23+
obfuscated = shellcode.toIPv6
24+
of MAC:
25+
obfuscated = shellcode.toMAC
26+
27+
if outfile == "stdout":
28+
stdout.write(obfuscated.join("\n"))
29+
else:
30+
outfile.writeFile(obfuscated.join("\n"))
31+
32+
import cligen; dispatch argParser, help={
33+
"obfuscation": "one of: uuid, ipv4, ipv6, mac",
34+
"filename": "a file to read from",
35+
"outfile": "file to write results to"},
36+
short={"obfuscation": 't'}

src/HellShellpkg/encryption.nim

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{.push raises: [].}
2+
import std/random
3+
import winim
4+
5+
6+
type
7+
USTRING = object
8+
Length, MaximumLength: DWORD
9+
Buffer: PVOID
10+
11+
proc makeRandomBytes(i: int): seq[uint8] =
12+
for k in 0 .. i:
13+
result.add(rand(255).uint8)
14+
15+
proc rc4EncryptNTAPI(data, key: PTR): NTSTATUS
16+
{.discardable, stdcall, dynlib: "Advapi32", importc: "SystemFunction032"}
17+
18+
proc rc4Encrypt*(key, payload: seq[uint8], winapi: bool): string {.raises: [OSError].} =
19+
if winapi:
20+
var
21+
winPayload = payload # need a deep copy because of in-place memory modification
22+
key = USTRING(
23+
Length: cast[int32](key.len),
24+
MaximumLength: cast[int32](key.len),
25+
Buffer: key.addr # can't use `ptr` because it is a generic
26+
)
27+
data = USTRING(
28+
Length: cast[int32](winPayload.len),
29+
MaximumLength: cast[int32](winPayload.len),
30+
Buffer: winPayload.addr
31+
)
32+
status = rc4EncryptNTAPI(data.addr, key.addr)
33+
if not status.NT_SUCCESS:
34+
echo &"[-] Encryption failed with code: {status}"
35+
raise newException(OSError, "Encryption failed using NTAPI")
36+
37+
result = $data

src/HellShellpkg/ioutils.nim

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import std / [ streams, sequtils ]
2+
3+
proc readFileToBytes*(fileLocation: string, ): seq[uint8] =
4+
let hFile = newFileStream(fileLocation)
5+
defer: hFile.close()
6+
result = result.toSeq()
7+
while not hFile.atEnd():
8+
result.add(hFile.readUint8())
9+

src/HellShellpkg/obfuscation.nim

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import std/[sequtils,strformat,strutils, sugar]
2+
3+
4+
proc toEvenHex(bytes: seq[uint8], sizeNeeded: int8): seq[string] =
5+
let
6+
hex = bytes.toSeq.mapIt(it.toHex.toLower)
7+
remainder = sizeNeeded - hex.len.mod(sizeNeeded)
8+
padding = @["90"].cycle(remainder)
9+
writeLine(stderr, &"[*] Shellcode is {hex.len} bytes, adding {remainder} NOPs to make UUIDs")
10+
11+
return concat(padding, hex) # add NOP sled to make the sequence evenly devisible
12+
13+
14+
proc toUUIDs*(bytes: seq[uint8]): seq[string] =
15+
let hex = bytes.toEvenHex(16)
16+
result = collect:
17+
for i in countup(0, hex.len-16, 16):
18+
let uuidGroups = hex[i ..< i+16].distribute(4)
19+
&"{uuidGroups[0].join}-{uuidGroups[1].join}-{uuidGroups[2].join}{uuidGroups[3].join}"
20+
21+
proc fromUUID*(uuid: string): seq[uint8] =
22+
let bytes = uuid
23+
.filterIt(it != '-')
24+
.distribute(16)
25+
.mapIt(fromHex[uint8](join(it)))
26+
result = collect(newSeq):
27+
for b in bytes: b
28+
29+
proc toMAC*(bytes: seq[uint8]): seq[string] =
30+
let hex = bytes.toEvenHex(8)
31+
for i in countup(0, hex.len-8, 8):
32+
let mac = hex[i ..< i+8].join("-")
33+
result.add(mac)
34+
35+
proc fromMAC*(mac: string): seq[uint8] =
36+
result = mac.split(".").mapIt(cast[uint8](it.parseUInt))
37+
38+
proc toIPv6*(bytes: seq[uint8]): seq[string] =
39+
let hex = bytes.toEvenHex(16)
40+
result = collect:
41+
for i in countup(0, hex.len-16, 16):
42+
let uuidGroups = hex[i ..< i+16].distribute(4)
43+
join(uuidGroups.mapIt(join(it)),":")
44+
#let uuid = &"{uuidGroups[0].join(":")}:{uuidGroups[1].join(":")}:{uuidGroups[2].join(":")}{uuidGroups[3].join(":")}"
45+
46+
proc fromIPv6*(ipv6: string): seq[uint8] =
47+
let bytes = ipv6
48+
.filterIt(it != ':')
49+
.distribute(16)
50+
.mapIt(fromHex[uint8](join(it)))
51+
result = collect:
52+
for b in bytes: b
53+
54+
proc toIPv4*(bytes: seq[uint8]): seq[string] =
55+
let
56+
remainder = 4 - bytes.len.mod(4)
57+
buffer = @[144'u8].cycle(remainder) # 144d = 90h (NOP)
58+
alignedBytes = concat(buffer, bytes)
59+
for i in countup(0, alignedBytes.len-4, 4):
60+
result.add(alignedBytes[i ..< i+4].join("."))
61+
62+
proc fromIPv4*(ipv4: string): seq[uint8] =
63+
result = ipv4.split(".").mapIt(cast[uint8](it.parseUInt))

tests/config.nims

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
switch("path", "$projectDir/../src")

tests/shellcode.bin

394 Bytes
Binary file not shown.

tests/test1.nim

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This is just an example to get you started. You may wish to put all of your
2+
# tests into a single file, or separate them into multiple `test1`, `test2`
3+
# etc. files (better names are recommended, just make sure the name starts with
4+
# the letter 't').
5+
#
6+
# To run these tests, simply execute `nimble test`.
7+
8+
import unittest, sequtils
9+
10+
import ../src/HellShellpkg/[obfuscation, ioutils]
11+
12+
test "to and from are the same":
13+
let
14+
shellcode = "tests/shellcode.bin".readFileToBytes()
15+
transformed = shellcode.toUUIDs.map(fromUUID).foldl(a & b)
16+
check transformed[transformed.len-shellcode.len .. ^1] == shellcode # have to slice off the NOPs

0 commit comments

Comments
 (0)