Skip to content

Commit

Permalink
Merge pull request #1752 from BishopFox/wiki_1.6_update
Browse files Browse the repository at this point in the history
Wiki 1.6 update
  • Loading branch information
moloch-- authored Jul 22, 2024
2 parents 2cd7a96 + b8cef5f commit 40dfa95
Show file tree
Hide file tree
Showing 32 changed files with 7,004 additions and 5 deletions.
1 change: 1 addition & 0 deletions docs/sliver-docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# generated files
public/sitemap.json
public/docs.json
public/tutorials.json
/www.zip

# code editor files
Expand Down
1 change: 1 addition & 0 deletions docs/sliver-docs/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const nextConfig = {
webpack: (config, { isServer }) => {
if (isServer) {
require('./prebuild/generate-docs');
require('./prebuild/generate-tutorials');
}
return config;
}
Expand Down
11 changes: 11 additions & 0 deletions docs/sliver-docs/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Navbar from "@/components/navbar";
import "@/styles/globals.css";
import { Docs } from "@/util/docs";
import { Tutorials } from "@/util/tutorials";
import { SearchContext, SearchCtx } from "@/util/search-context";
import { Themes } from "@/util/themes";
import { faExternalLink } from "@fortawesome/free-solid-svg-icons";
Expand Down Expand Up @@ -42,6 +43,16 @@ export default function App({ Component, pageProps }: AppProps) {
},
});

queryClient.prefetchQuery({
queryKey: ["tutorials"],
queryFn: async (): Promise<Tutorials> => {
const res = await fetch("/tutorials.json");
const tutorials: Tutorials = await res.json();
search.addTutorials(tutorials);
return tutorials;
},
});

return (
<NextUIProvider>
<NextThemesProvider attribute="class" defaultTheme={getThemeState()}>
Expand Down
149 changes: 145 additions & 4 deletions docs/sliver-docs/pages/tutorials/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,152 @@
import MarkdownViewer from "@/components/markdown";
import { Tutorials } from "@/util/tutorials";
import { Themes } from "@/util/themes";
import { faSearch } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
Card,
CardBody,
CardHeader,
Divider,
Input,
Listbox,
ListboxItem,
ScrollShadow,
} from "@nextui-org/react";
import { useQuery } from "@tanstack/react-query";
import Fuse from "fuse.js";
import { NextPage } from "next";
import { useTheme } from "next-themes";
import Head from "next/head";
import { useSearchParams } from "next/navigation";
import { useRouter } from "next/router";
import React from "react";

const TutorialsIndexPage: NextPage = () => {
const { theme } = useTheme();
const router = useRouter();

const { data: tutorials, isLoading } = useQuery({
queryKey: ["tutorials"],
queryFn: async (): Promise<Tutorials> => {
const res = await fetch("/tutorials.json");
return res.json();
},
});

const params = useSearchParams();
const [name, setName] = React.useState("");
const [markdown, setMarkdown] = React.useState("");

React.useEffect(() => {
const _name = params.get("name");
setName(_name || "");
setMarkdown(tutorials?.tutorials.find((tutorial) => tutorial.name === _name)?.content || "");
}, [params, tutorials]);

const [filterValue, setFilterValue] = React.useState("");
const fuse = React.useMemo(() => {
return new Fuse(tutorials?.tutorials || [], {
keys: ["name"],
threshold: 0.3,
});
}, [tutorials]);

const visibleTutorials = React.useMemo(() => {
if (filterValue) {
// Fuzzy match display names
const fuzzy = fuse.search(filterValue).map((r) => r.item);
return fuzzy;
}
return tutorials?.tutorials || [];
}, [tutorials, fuse, filterValue]);

const listboxClasses = React.useMemo(() => {
if (theme === Themes.DARK) {
return "p-0 gap-0 divide-y divide-default-300/50 dark:divide-default-100/80 bg-content1 overflow-visible shadow-small rounded-medium";
} else {
return "border p-0 gap-0 divide-y divide-default-300/50 dark:divide-default-100/80 bg-content1 overflow-visible shadow-small rounded-medium";
}
}, [theme]);

if (isLoading || !tutorials) {
return <div>Loading...</div>;
}

const IndexPage: NextPage = () => {
return (
<div>
<p>Coming soon...</p>
<div className="grid grid-cols-12">
<Head>
<title>Sliver Tutorial: {name}</title>
</Head>
<div className="col-span-3 mt-4 ml-4 h-screen sticky top-20">
<div className="flex flex-row justify-center text-lg gap-2">
<Input
placeholder="Filter..."
startContent={<FontAwesomeIcon icon={faSearch} />}
value={filterValue}
onChange={(e) => setFilterValue(e.target.value)}
isClearable={true}
onClear={() => setFilterValue("")}
/>
</div>
<div className="mt-2">
<ScrollShadow>
<div className="max-h-[70vh]">
<Listbox
aria-label="Toolbox Menu"
className={listboxClasses}
itemClasses={{
base: "px-3 first:rounded-t-medium last:rounded-b-medium rounded-none gap-3 h-12 data-[hover=true]:bg-default-100/80",
}}
>
{visibleTutorials.map((tutorial) => (
<ListboxItem
key={tutorial.name}
value={tutorial.name}
onClick={() => {
router.push({
pathname: "/tutorials",
query: { name: tutorial.name },
});
}}
>
{tutorial.name}
</ListboxItem>
))}
</Listbox>
</div>
</ScrollShadow>
</div>
</div>
<div className="col-span-9">
{name !== "" ? (
<Card className="mt-8 ml-8 mr-8 mb-8">
<CardHeader>
<span className="text-3xl">{name}</span>
</CardHeader>
<Divider />
<CardBody>
<MarkdownViewer
key={name || `${Math.random()}`}
markdown={markdown || ""}
/>
</CardBody>
</Card>
) : (
<div className="grid grid-cols-3">
<div className="col-span-1"></div>
<div className="col-span-1 mt-8 text-2xl text-center">
Welcome to the Sliver Tutorials!
<div className="text-xl text-gray-500">
Please select a chapter
</div>
</div>
<div className="col-span-1"></div>
</div>
)}
</div>
</div>
);
};

export default IndexPage;
export default TutorialsIndexPage;
88 changes: 88 additions & 0 deletions docs/sliver-docs/pages/tutorials/md/1 - Getting Started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# This course is intented for the 1.6 version of Sliver, which is not yet published

`sliver-server` is the binary you want to use to run the Sliver C2 server, `sliver-client` is solely a client to connect to a Sliver C2 server. Sliver server also acts as a client on its own, so you don’t necessarily run sliver server and client separately.

First time running Sliver will take a couple seconds as its retrieving its dependencies, consecutive executions will be much faster. Go ahead and launch the `sliver-server`.

```asciinema
{"src": "/asciinema/startup.cast", "cols": "132", "rows": "28", "idleTimeLimit": 8}
```

Let's take a couple minutes to discuss what Sliver actually is and how its setup.

![Alt text](/images/Architecture.png)

Now that Sliver is running, lets generate and execute your first implant to try out some of the basic features of Sliver, for now we’re going to run everything on the local host.

Here's what we're going to do:
* Generate your implant using the `generate` command as shown below.
* Start HTTP listener on port 80
* Execute implant in a separate terminal

```asciinema
{"src": "/asciinema/first-implant.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```

Now let’s select our implant and run our first command using the `use` command.

```bash
[server] sliver > use
? Select a session or beacon:
SESSION 1884a365 RELATED_EARDRUM [::1]:49153 test.local tester darwin/amd64
[*] Active session RELATED_EARDRUM (1884a365-085f-4506-b28e-80c481730fd0)

[server] sliver (RELATED_EARDRUM) > pwd

[*] /Users/tester/tools
```

Once you have reached this point, go ahead and explore some of the commands listed below. In each case first checkout the commands help using the **`-h`** flag then try it out!

```bash
Exploring and interacting with the filesystem

Filesystem
cat Dump file to stdout
cd Change directory
cp Copy a file
download Download a file
grep Search for strings that match a regex within a file or directory
head Grab the first number of bytes or lines from a file
ls List current directory
memfiles List current memfiles
mkdir Make a directory
mount Get information on mounted filesystems
mv Move or rename a file
pwd Print working directory
rm Remove a file or directory
tail Grab the last number of bytes or lines from a file
upload Upload a file
```

```asciinema
{"src": "/asciinema/filesystem.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```

Getting some environmental information
```bash
Info
env List environment variables
getgid Get session process GID
getpid Get session pid
getuid Get session process UID
info Get session info
ping Send round trip message to implant (does not use ICMP)
screenshot Take a screenshot
whoami Get session user execution context
```
Execute a binary

```asciinema
{"src": "/asciinema/execute.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```

Running an interactive shell

```asciinema
{"src": "/asciinema/shell.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```
95 changes: 95 additions & 0 deletions docs/sliver-docs/pages/tutorials/md/2 - Beacons vs Sessions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# This course is intented for the 1.6 version of Sliver, which is not yet published

Sliver implants support two types of connections, sessions and beacons.

Sessions use long-poling connections, which means they use a single TCP connection which is constantly open. Beacons on the other hand call back periodically, and will sleep when not active which can help keep their presence hidden.

Typically during an engagement you will want to deploy a beacon on the target system, and switch to a session while doing more active enumeration activities.

Let’s start with generating and deploying a beacon using `http`.

```asciinema
{"src": "/asciinema/beacon_generation.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```

You can see the beacon callback times either in the `info` command or using `beacons watch`.

```bash
[server] sliver > beacons watch

ID Name Transport Username Operating System Last Check-In Next Check-In
========== =============== =========== ================= ================== =============== ===============
942c647c TIRED_GIRAFFE http(s) tester darwin/amd64 52s 12s

```

Beacon callback times and jitter can be set either during generation or on the fly using the `reconfig` command.

The example below sets the callback time to 5s with a 1s jitter.

```bash
[server] sliver (TIRED_GIRAFFE) > reconfig -i 5s -j 1s

[*] Tasked beacon TIRED_GIRAFFE (b8aa6fd8)

[+] TIRED_GIRAFFE completed task b8aa6fd8

[*] Reconfigured beacon

[server] sliver (TIRED_GIRAFFE) > info

Beacon ID: 942c647c-8409-4877-9fa2-b84a7f27ad45
Name: TIRED_GIRAFFE
Hostname: tester.local
UUID: c6de1a44-016a-5fbe-b76a-da56af41316d
Username: tester
UID: 501
GID: 20
PID: 55879
OS: darwin
Version:
Locale:
Arch: amd64
Active C2: https://127.0.0.1
Remote Address: 127.0.0.1:51803
Proxy URL:
Interval: 1m0s
Jitter: 30s
First Contact: Wed Apr 19 01:14:21 CEST 2023 (10m30s ago)
Last Checkin: Wed Apr 19 01:18:20 CEST 2023 (6m31s ago)
Next Checkin: Wed Apr 19 01:19:46 CEST 2023 (5m5s ago)
```

Commands issued for beacons can be viewed using `tasks`, the task state will indicate wether the command has completed or not. The results of previously run tasks can be viewed using `tasks fetch`.

```asciinema
{"src": "/asciinema/beacon_tasks.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```

Session can be spun up using the `interractive` command.

```asciinema
{"src": "/asciinema/beacon_interractive.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8}
```

Because of the differences between sessions and beacons, certain commands like `upload` or `download` are slower on beacons due to the callback time. Others such as socks5 are not supported and only allowed for sessions. As a rule of thumb anything requiring higher network bandwith should be run from a session.

Let’s switch to our newly created session and spin-up a `socks5` proxy.

```bash

socks
[server] sliver (TIRED_GIRAFFE) > use

? Select a session or beacon: SESSION 131a60b9 TIRED_GIRAFFE 127.0.0.1:51969 tester.local tester darwin/amd64
[*] Active session TIRED_GIRAFFE (131a60b9-db4f-4913-9064-18a17a0f09ab)

[server] sliver (TIRED_GIRAFFE) > socks5 start

[*] Started SOCKS5 127.0.0.1 1081
⚠️ In-band SOCKS proxies can be a little unstable depending on protocol
```

You can then point your browser to port 1081 to tunnel traffic through the implant to your target’s local network.

Try out some of the previous commands and compare behaviour on beacons and sessions. Once you are done, you should remember to close your session using the `close` command.
Loading

0 comments on commit 40dfa95

Please sign in to comment.