From 01f8d33fbb3df09079798a4fdd4cbcd7af2c2ddd Mon Sep 17 00:00:00 2001 From: Nick McClendon Date: Mon, 22 Jul 2024 22:26:39 -0500 Subject: [PATCH] Initial commit --- .vscode/extensions.json | 6 ++ .vscode/tasks.json | 23 +++++ CONTRIBUTING.md | 33 ++++++ LICENSE | 201 +++++++++++++++++++++++++++++++++++ README.md | 53 ++++++++++ cmd/main.go | 134 ++++++++++++++++++++++++ go.mod | 3 + shelidate.bin | Bin 0 -> 2080 bytes shelidate.go | 191 ++++++++++++++++++++++++++++++++++ shellcode/main.S | 21 ++++ shellcode/main.c | 224 ++++++++++++++++++++++++++++++++++++++++ 11 files changed, 889 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/tasks.json create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 cmd/main.go create mode 100644 go.mod create mode 100644 shelidate.bin create mode 100644 shelidate.go create mode 100644 shellcode/main.S create mode 100644 shellcode/main.c diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..50f33e0 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "golang.go", + "ms-vscode.cpptools" + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7b77ddc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,23 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build shelidate.exe", + "type": "shell", + "command": "gcc shellcode/main.c -o shelidate.exe --entry=entry -nostdlib -ffunction-sections -fno-asynchronous-unwind-tables -fno-ident '-Wl,--strip-all,--no-seh,-Tshellcode/main.S'", + "problemMatcher": [ + "$gcc" + ] + }, + { + "label": "Build shelidate.bin", + "type": "shell", + "command": "objcopy -O binary --only-section=.text shelidate.exe shelidate.bin", + "problemMatcher": [ + "$gcc" + ] + } + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b16bd94 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# How to contribute + +We'd love to accept your patches and contributions to this project. + +## Before you begin + +### Sign our Contributor License Agreement + +Contributions to this project must be accompanied by a +[Contributor License Agreement](https://cla.developers.google.com/about) (CLA). +You (or your employer) retain the copyright to your contribution; this simply +gives us permission to use and redistribute your contributions as part of the +project. + +If you or your current employer have already signed the Google CLA (even if it +was for a different project), you probably don't need to do it again. + +Visit to see your current agreements or to +sign a new one. + +### Review our community guidelines + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google/conduct/). + +## Contribution process + +### Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..34dd22f --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# shelidate + +A shellcode integration testing harness. shelidate can be used standalone to confirm payload callbacks without standing up a full command and control framework or integrated into the testing process to ensure payloads execute properly. + +## Usage + +``` +Usage of shelidate.exe: + -address string + shellcode listener address (default "127.0.0.1:1337") + -command string + command to execute while listening, use {{.Shellcode}} to substitute the shellcode file + -timeout string + timeout duration (only used if commmand is specified) (default "30s") +``` + +### Examples + +Generate shellcode that calls back to `127.0.0.1:1337` and listen indefinitely: + +``` +shelidate.exe +``` + +Generate shellcode, run the command `shellcode_runner.exe C:\Path\To\Shellcode`, and time out after 30 seconds + +``` +shelidate.exe -command 'shellcode_runner.exe {{.Shellcode}}' +``` + +## Setup + +shelidate expects Go 1.22 on Windows to build. shelidate can be build with + +``` +go build -o shelidate ./cmd/... +``` + +### Building shellcode + +[MinGW-w64](https://www.mingw-w64.org/) must be installed and `gcc` and `objcopy` must be available on the path to rebuild the shellcode, `shelidate.bin`. + +The initial executable can be built with: + +``` +gcc shellcode/main.c -o shelidate.exe --entry=entry -nostdlib -ffunction-sections -fno-asynchronous-unwind-tables -fno-ident '-Wl,--strip-all,--no-seh,-Tshellcode/main.S' +``` + +The shellcode can be extracted with: + +``` +objcopy -O binary --only-section=.text shelidate.exe shelidate.bin +``` diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..84afc6a --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,134 @@ +// Copyright 2024 Google LLC + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package main + +import ( + "bytes" + "context" + "flag" + "html/template" + "log" + "math/rand" + "os" + "os/exec" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/mandiant/shelidate" +) + +var address = flag.String("address", "127.0.0.1:1337", "shellcode listener address") +var command = flag.String("command", "", "command to execute while listening, use {{.Shellcode}} to substitute the shellcode file") +var timeout = flag.String("timeout", "30s", "timeout duration (only used if commmand is specified)") + +type Variables struct { + Shellcode string +} + +func main() { + flag.Parse() + + var svr shelidate.Server + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + wg := new(sync.WaitGroup) + + if err := svr.Listen(*address); err != nil { + log.Fatalf("failed to start listener - address: %v - error: %v", *address, err) + } + + log.Printf("callback server listening - address: %v", *address) + + dir, err := os.Getwd() + if err != nil { + log.Fatalf("failed to get working directory - error: %v", err) + } + + shellcode, err := svr.Generate(dir, rand.Uint32()) + if err != nil { + log.Fatalf("failed to generate shellcode - error: %v", err) + } + defer os.Remove(shellcode.Path) + + log.Printf("generated test shellcode: %v", shellcode.Path) + + var cmd string + if *command != "" { + tmpl, err := template.New("command").Parse(*command) + if err != nil { + log.Fatalf("failed to template provided command - command: %v - error: %v", command, err) + } + + var buf bytes.Buffer + if err := tmpl.Execute( + &buf, + Variables{ + Shellcode: shellcode.Path, + }, + ); err != nil { + log.Fatalf("failed to template provided command - command: %v - error: %v", command, err) + } + + cmd = buf.String() + } + + wg.Add(1) + + var ctx context.Context + var cancel context.CancelFunc + + if cmd != "" { + duration, err := time.ParseDuration(*timeout) + if err != nil { + log.Fatalf("failed to parse provided timeout - timout: %v - error: %v", *timeout, err) + } + ctx, cancel = context.WithTimeout(context.Background(), duration) + } else { + ctx, cancel = context.WithCancel(context.Background()) + } + + go func() { + defer wg.Done() + defer svr.Close() + defer shellcode.Cancel() + defer cancel() + + for { + select { + case <-c: + return + case <-ctx.Done(): + return + case <-shellcode.Recv: + log.Printf("test shellcode checked in") + if cmd != "" { + time.Sleep(500 * time.Millisecond) + return + } + } + } + }() + + if cmd != "" { + log.Printf("running the command: %v", cmd) + if err := exec.CommandContext(ctx, "C:\\Windows\\System32\\cmd.exe", "/c", cmd).Run(); err != nil { + log.Fatalf("command failed to run: %v", err) + } + } + + wg.Wait() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d998541 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/mandiant/shelidate + +go 1.22.5 diff --git a/shelidate.bin b/shelidate.bin new file mode 100644 index 0000000000000000000000000000000000000000..1b2cde0e2f34c3e9486911404d3e24ca1293e1bc GIT binary patch literal 2080 zcma)7O=ufe5MHTi4hd9C2}Oq<)Ut%M6l0tcY?6aScJYI##l#jVgkn3=il!D;Dy_gd z1RPeTUbZSan6}VMN-jBuQewG;u#%xppa(a%f)6>Qpdb-+R6~OLeQ#IQIz>={-+c4U z&zmSW@&V0elVD8EaQ%q;PbtvZre|WK82yd1{e` zkp2?%SF)tWrTNsnwOq1DFM`fn6(%8F%&wTE7eHS&Efm+t7FSoztc4PEEe(3MY_8^h z)3pn<6^doET+GsT7Pj*%rlquBpfSQ}wyzwa^oJs9TmF;WK!^R}o4%dHpih7{UGDNcSW#VMcsFfFx@PD?Q{ zCB@`~6jQnsANww6d@=2hMz~2#Mc3wp%ft2()C4sgn6s`WsU(Hn#(Z_{Gio@JbNr`- zceDNXtHD5Ed5;fGlbv%uv^^Q~f6`4NL*@4C-K_`x@Ou&Lm+B_Zi7Z>EiU__;jVFLl z-1SXtnPVK-Hx86o^*$6gb1-tE|Gt|{IIR)KwE(Auxt`Cx8|EJF8C~R4I+tPWyGq#R z2{(g318r=!pQ9Cc$4Tg1sMxkAYA5)!rhs{fYD2M|_pm6vD31OS+vsv*P|FE7)17IR Iz8`ktALl{H!2kdN literal 0 HcmV?d00001 diff --git a/shelidate.go b/shelidate.go new file mode 100644 index 0000000..1751967 --- /dev/null +++ b/shelidate.go @@ -0,0 +1,191 @@ +// Copyright 2024 Google LLC + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package shelidate + +import ( + "bytes" + _ "embed" + "encoding/binary" + "fmt" + "io" + "math/big" + "net" + "os" + "path/filepath" + "strconv" + "sync" +) + +//go:embed shelidate.bin +var shelidate []byte + +func inetaton(host string) uint32 { + res := big.NewInt(0) + res.SetBytes(net.ParseIP(host).To4()) + return uint32(res.Uint64()) +} + +type val struct{} + +type Server struct { + address string + l net.Listener + mu sync.Mutex + ch map[uint32]chan<- val +} + +type Shellcode struct { + Path string + Recv <-chan val + Cancel Cancel +} + +type Cancel func() + +func (s *Server) Listen(address string) error { + var err error + s.l, err = net.Listen("tcp", address) + if err != nil { + return err + } + s.address = address + go func() { + for { + conn, err := s.l.Accept() + if err != nil { + return + } + + go s.handle(conn) + } + }() + return nil +} + +func (s *Server) Close() error { + return s.l.Close() +} + +func (s *Server) handle(conn net.Conn) error { + defer conn.Close() + var value uint32 + if err := binary.Read(conn, binary.LittleEndian, &value); err != nil { + return err + } + + s.mu.Lock() + if s.ch != nil { + ch, ok := s.ch[value] + s.mu.Unlock() + if ok { + ch <- val{} + } + } else { + s.mu.Unlock() + } + + return nil +} + +func (s *Server) Generate(dir string, value uint32) (Shellcode, error) { + if s.address == "" { + return Shellcode{}, fmt.Errorf("must be listening before generating shellcode") + } + + s.mu.Lock() + defer s.mu.Unlock() + + if s.ch == nil { + s.ch = make(map[uint32]chan<- val) + } + + _, ok := s.ch[value] + if ok { + return Shellcode{}, fmt.Errorf("value already in use") + } + + host, port, err := net.SplitHostPort(s.address) + if err != nil { + return Shellcode{}, fmt.Errorf("failed to parse listen address: %v", err) + } + + uPort, err := strconv.ParseUint(port, 10, 32) + if err != nil { + return Shellcode{}, fmt.Errorf("failed to parse listen address: %v", err) + } + + uHost := inetaton(host) + + var b bytes.Buffer + if _, err := b.Write([]byte{0xEB, 0x13, 0x58, 0xB9}); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if err := binary.Write(&b, binary.BigEndian, uint16(uPort)); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if _, err := b.Write([]byte{0x00, 0x00}); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if err := b.WriteByte(0xBA); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if err := binary.Write(&b, binary.BigEndian, uHost); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if _, err := b.Write([]byte{0x41, 0xB8}); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if err := binary.Write(&b, binary.LittleEndian, value); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + if _, err := b.Write([]byte{0xFF, 0xE0, 0xE8, 0xE8, 0xFF, 0xFF, 0xFF}); err != nil { + return Shellcode{}, fmt.Errorf("failed to prep shellcode: %v", err) + } + + out := filepath.Join(dir, fmt.Sprintf("shellcode_%d.bin", value)) + + fd, err := os.Create(out) + if err != nil { + return Shellcode{}, fmt.Errorf("failed to create shellcode file: %v", err) + } + defer fd.Close() + + if _, err := io.Copy(fd, &b); err != nil { + return Shellcode{}, fmt.Errorf("failed to write shellcode file: %v", err) + } + + if _, err := fd.Write(shelidate); err != nil { + return Shellcode{}, fmt.Errorf("failed to write shellcode file: %v", err) + } + + ch := make(chan val) + s.ch[value] = ch + + return Shellcode{ + Path: out, + Recv: ch, + Cancel: func() { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.ch, value) + }, + }, nil +} diff --git a/shellcode/main.S b/shellcode/main.S new file mode 100644 index 0000000..4e6ace2 --- /dev/null +++ b/shellcode/main.S @@ -0,0 +1,21 @@ +/* Copyright 2024 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ +SECTIONS +{ + .text 0x140001000: + { + *(.text$entry) + *(.text*) + } +} diff --git a/shellcode/main.c b/shellcode/main.c new file mode 100644 index 0000000..6f99a14 --- /dev/null +++ b/shellcode/main.c @@ -0,0 +1,224 @@ +// Copyright 2024 Google LLC + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include + +#pragma comment (lib, "Ws2_32.lib") + +// Dependency Loading +typedef PVOID(WINAPI* FnGetProcAddress)(HMODULE mod, char* apiName); +typedef HMODULE(WINAPI* FnLoadLibraryA)(char* moduleName); +typedef HMODULE(WINAPI* FnGetModuleHandleA)(LPCSTR lpModuleName); +typedef void(WINAPI* FnSleep)(DWORD dwMilliseconds); +typedef void(WINAPI* FnExitProcess)(UINT uExitCode); +// sockets +typedef int(WINAPI* FnWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData); +typedef SOCKET(WSAAPI* FnWSASocketA)(int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags); +typedef int(WSAAPI* FnConnect)(SOCKET s, const SOCKADDR* name, int namelen); +typedef int(WSAAPI* FnSend)(SOCKET s, const char* buf, int len, int flags); +typedef int(WSAAPI* FnCloseSocket)(SOCKET s); + +DWORD entry(int port, unsigned long host, int nonce); +PPEB GetPEB(); +PVOID GetKernel32DLL(PPEB ppeb); +HMODULE MemGetProcAddress(PVOID pModule, PCSTR funcName); + +DWORD entry(int port, unsigned long host, int nonce) { + PVOID kernel32 = NULL; + FnLoadLibraryA myLoadLibrary = NULL; + FnGetProcAddress myGetProcAddress = NULL; + FnSleep mySleep = NULL; + FnExitProcess myExitProcess = NULL; + + FnWSAStartup myWSAStartup = NULL; + FnWSASocketA myWSASocketA = NULL; + FnConnect myConnect = NULL; + FnSend mySend = NULL; + FnCloseSocket myClose = NULL; + + WSADATA wsaData; + SOCKET soc; + struct sockaddr_in remote; + + char kernel32Str[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0 }; + char loadLibrary[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0 }; + char getProcAddress[] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0 }; + char sleep[] = { 'S', 'l', 'e', 'e', 'p', 0 }; + char exitProcess[] = { 'E', 'x', 'i', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 0 }; + + char ws2_32dll[] = { 'W', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0 }; + char wsaStartup[] = { 'W', 'S', 'A', 'S', 't', 'a', 'r', 't', 'u', 'p', 0 }; + char wsaSocketA[] = { 'W', 'S', 'A', 'S', 'o', 'c', 'k', 'e', 't', 'A', 0 }; + char connect[] = { 'c', 'o', 'n', 'n', 'e', 'c', 't', 0 }; + char send[] = { 's', 'e', 'n', 'd', 0 }; + char close[] = { 'c', 'l', 'o', 's', 'e', 's', 'o', 'c', 'k', 'e', 't', 0 }; + + kernel32 = GetKernel32DLL(GetPEB()); + + myGetProcAddress = (FnGetProcAddress)MemGetProcAddress(kernel32, getProcAddress); + myLoadLibrary = (FnLoadLibraryA)myGetProcAddress(kernel32, loadLibrary); + + if (myLoadLibrary == NULL || myGetProcAddress == NULL) { + return 0; + } + + mySleep = (FnSleep)myGetProcAddress(kernel32, sleep); + myExitProcess = (FnExitProcess)myGetProcAddress(kernel32, exitProcess); + + HMODULE winsock = myLoadLibrary(ws2_32dll); + if (!winsock) { + myExitProcess(2); + } + + myWSAStartup = (FnWSAStartup)myGetProcAddress(winsock, wsaStartup); + myWSASocketA = (FnWSASocketA)myGetProcAddress(winsock, wsaSocketA); + myConnect = (FnConnect)myGetProcAddress(winsock, connect); + mySend = (FnSend)myGetProcAddress(winsock, send); + myClose = (FnCloseSocket)myGetProcAddress(winsock, close); + + if (myWSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + myExitProcess(3); + } + + soc = myWSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); + if (soc == INVALID_SOCKET) { + myExitProcess(4); + } + + remote.sin_family = AF_INET; + remote.sin_addr.s_addr = host; + remote.sin_port = port; + + if (myConnect(soc, (SOCKADDR*)&remote, sizeof(remote))) { + myExitProcess(5); + } + + if (mySend(soc, (char*)&nonce, sizeof(int), 0) == SOCKET_ERROR) { + myExitProcess(6); + } + + // sleep for 100 milliseconds, so we know the send is going to complete + mySleep(100); + + myClose(soc); + + myExitProcess(0); + + return 0; +} + +PPEB GetPEB() { +#if defined(_WIN64) + return (PPEB)__readgsqword(0x60); +#else + return (PPEB)__readfsdword(0x30); +#endif +} + +wchar_t* mywcsistr(wchar_t* string, wchar_t* substring) +{ + wchar_t* a; + wchar_t* b; + + if (*substring == 0) + { + return string; + } + + while (*string != 0) + { + b = substring; + + if (*string != *b && *string != (*b ^ 0x20)) + { + *string++; + continue; + } + a = string; + + while (*b != 0) + { + if (*a != *b && *a != (*b ^ 0x20)) + { + break; + } + + *a++; + *b++; + + if (*b == 0) + { + return string; + } + } + + *string++; + } + return NULL; +} + +int mystrcmp(const char* string1, const char* string2) +{ + + while(*string1 != 0 && (*string1 == *string2)) { + string1++; + string2++; + } + + return *string1 - *string2; +} + +PVOID GetKernel32DLL(PPEB ppeb) { + wchar_t kernel32[] = { 'K', 'E', 'R', 'N', 'E', 'L', '3', '2', '.', 'D', 'L', 'L', 0 }; + PPEB_LDR_DATA pLdr = ppeb->Ldr; + + PLIST_ENTRY pNextModule = &pLdr->InMemoryOrderModuleList; + PLIST_ENTRY pCurEntry = pNextModule->Flink; + PLDR_DATA_TABLE_ENTRY pDataTableEntry = CONTAINING_RECORD(pCurEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + + do { + if (mywcsistr(pDataTableEntry->FullDllName.Buffer, kernel32) != NULL) { + return pDataTableEntry->DllBase; + } + pNextModule = &(pDataTableEntry->InMemoryOrderLinks); + pCurEntry = pNextModule->Flink; + pDataTableEntry = CONTAINING_RECORD(pCurEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + } while (pDataTableEntry->DllBase != NULL); + return NULL; +} + +HMODULE MemGetProcAddress(PVOID pModule, PCSTR funcName) { + PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)pModule + ((PIMAGE_DOS_HEADER)pModule)->e_lfanew); + DWORD dwExportDirRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + if (dwExportDirRVA != 0) { + PIMAGE_EXPORT_DIRECTORY pExportsDir = (PIMAGE_EXPORT_DIRECTORY)(((ULONG_PTR)pModule) + dwExportDirRVA); + PDWORD pdwNameBase = (PDWORD)((ULONG_PTR)pModule + pExportsDir->AddressOfNames); + PWORD pdwOrdinalBase = (PWORD)((ULONG_PTR)pModule + pExportsDir->AddressOfNameOrdinals); + PDWORD pdwFunctionBase = (PDWORD)((ULONG_PTR)pModule + pExportsDir->AddressOfFunctions); + for (int i = 0; i < pExportsDir->NumberOfFunctions; i++) { + PCSTR pFunctionName = (PCSTR)(*pdwNameBase + (ULONG_PTR)pModule); + if (!mystrcmp(funcName, pFunctionName)) { + return (HMODULE)((ULONG_PTR)pModule + *((PDWORD)(pdwFunctionBase + *pdwOrdinalBase))); + } + pdwOrdinalBase++; + pdwNameBase++; + } + } + return NULL; +} +