web ctf中的计算器

web ctf中的计算器

web ctf中的计算器

1 简介

某ctf的web题是计算器,主要就是考脚本编写能力,自动化提交,整体还算简单。 服务端的php文件

2 实现数学表达式计算

使用instaparse这个库,写parser非常方便,虽然有点杀鸡用牛刀,代码如下:

 1: (require '[instaparse.core :as insta :refer [defparser]])
 2: 
 3: (defparser ques-exp
 4:   "expr = add-sub '='
 5: <add-sub> = mul-div | add | sub
 6: add = add-sub <'+'> mul-div
 7: sub = add-sub <'-'> mul-div
 8: <mul-div> = term | mul | div
 9: mul = mul-div <'*'> term
10: div = mul-div <'/'> term
11: <term> = number
12: number = #'[0-9]+'
13: "
14:   :auto-whitespace :standard ;; 忽略空格
15:   )
16: 
17: ;;; 测试解析器
18: (ques-exp "234 + 55 * 28 = ")
19: ;; => [:expr [:add [:number "234"] [:mul [:number "55"] [:number "28"]]] "="]
20: 
21: (defn eval-exp
22:   "执行表达式"
23:   [exp-str]
24:   (->> (ques-exp exp-str)
25:        (insta/transform {:add +
26:                          :sub -
27:                          :mul *
28:                          :div /
29:                          :number clojure.edn/read-string
30:                          :expr (fn [a _] a) ;; 忽略右边的=
31:                          :sign nil})))
32: 
33: (eval-exp "234 + 55 * 28 = ")
34: ;; => 1774
35: 
36: (eval-exp "2 * 3 / 2 - 8 + 6 / 3 = ")
37: ;; => -3

3 请求表达式和提交计算结果

接下来就是请求页面,解析出表达式,并提交结果:

 1: (require '[reaver :as html]) ;; 使用Jsoup解析html
 2: (require '[clj-http.client :as http]) ;; http请求
 3: (require '[clj-http.cookies :as cookies])
 4: 
 5: ;; 使用统一的cookie,用于保存session
 6: (def cs (cookies/cookie-store))
 7: 
 8: (def default-header
 9:   {:headers {"User-Agent" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.50 Safari/537.36"
10:              "Accept-Charset" "utf-8"}
11:    ;; 使用本地代理,方便查找问题
12:    :proxy-host "127.0.0.1"
13:    :proxy-port 8080
14:    :cookie-policy :standard
15:    :insecure? true
16:    })
17: 
18: (def ctf-u "http://192.168.47.129/web/html/index.php")
19: 
20: (defn extract-exp
21:   "从html中提取出表达式字符串"
22:   [html]
23:   (some-> (html/parse html)
24:           (html/extract [] "form > div" html/text)
25:           (->> (apply str))))
26: 
27: (defn get-question
28:   "获取问题"
29:   []
30:   (-> (http/get ctf-u (merge default-header {:cookie-store cs}))
31:       :body
32:       extract-exp))
33: 
34: (defn post-ans
35:   "提交答案"
36:   [ans]
37:   (-> (http/post ctf-u (merge default-header
38:                               {:cookie-store cs
39:                                :form-params ans}))
40:       :body))
41: 
42: 
43: ;; 提交一次测试
44: (get-question)
45: ;; => "+3572241+1162006+6727538*7357031-2782980-5908042+5687297*3471162+9574274="
46: ;; => "+3688345*6914278-7003441+7001140+2403633*2570857+7772803-1273673*2507819="
47: 
48: ;; 这次的题目需要前面再加一个数字
49: (eval-exp (str "123456" *1))
50: ;; => 69236240589747
51: 
52: ;; 提交一次请求,返回"must input some big number ~"
53: (post-ans {:ans *1
54:            :input 123456})

看后面的提示<!–the big number is the fist prime after 1000000 –>,需要计算素数:

 1: (def certainty 10)
 2: 
 3: (defn prime? [n]
 4:   "n是否为一个素数"
 5:   (.isProbablePrime (BigInteger/valueOf n) certainty))
 6: 
 7: (defn gen-prime
 8:   "从start开始产生一个素数"
 9:   [start]
10:   (first
11:    (filter prime?
12:            (range start Integer/MAX_VALUE))))
13: 
14: (gen-prime 20)
15: ;; => 23
16: 
17: (def i1 (gen-prime 1000000))
18: 
19: ;; 再请求一次
20: (->> (get-question)
21:      (str i1)
22:      eval-exp
23:      (hash-map :input i1 :ans)
24:      post-ans)
25: 
26: ;; 返回结果还是不对,当然看源码可以知道,生成的素数位数不对,少个0。
27: ;; 再来一次
28: (def i1 (gen-prime 10000000))
29: (->> (get-question)
30:      (str i1)
31:      eval-exp
32:      (hash-map :input i1 :ans)
33:      post-ans)
34: ;;; 这一次只有slow down的消息,证明提交的input数字是对的

4 循环提交

单次提交测试没有问题,就可以循环提交计算结果,直到返回的页面中没有提问,就算计算完成:

 1: ;; 添加了better-cond依赖,为了使用cond let子句
 2: (refer-clojure :exclude '[cond])
 3: (require '[better-cond.core :refer [cond]])
 4: 
 5: (defn process-answer
 6:   " 不断请求答案,直到返回的页面中没有提问
 7:   `format-fn` 格式化请求返回的表达式
 8:   `answer-fn` 格式化提交的form内容"
 9:   [{:keys [format-fn answer-fn]
10:     :or {format-fn identity
11:          answer-fn #(hash-map :ans %)}}]
12:   (loop [ques (get-question)
13:          result ""]
14:     (cond
15:       (empty? ques) result
16: 
17:       ;; 计算表达式
18:       :let [ans (-> (format-fn ques)
19:                     (doto println)
20:                     (eval-exp))]
21: 
22:       ;; 表达式计算错误
23:       (insta/failure? ans) (println :process "no eval result for" ques)
24: 
25:       ;; 提交结果
26:       :let [r (-> (answer-fn ans)
27:                   (post-ans))]
28: 
29:       (do
30:         (println :process "question:" ques "anser:" ans)
31:         (recur (extract-exp r)
32:                r)))))
33: 
34: (process-answer {:format-fn #(str i1 %)
35:                  :answer-fn #(hash-map :input i1 :ans %)})
36: 

可以看到post提交答案,返回的都是slow down,现在加入延时,延时数字要自己调整,当然看了代码才知道是2-3秒:

1: (process-answer {:format-fn #(str i1 %)
2:                  :answer-fn (fn [e]
3:                               (Thread/sleep 2000.)
4:                               {:ans e
5:                                :input i1})})
6: ;; => "
		<script language="javascript">  
		alert("right answer");  
	     </script> got flag....................."

5 总结

考察的就是基本的脚本编程能力,http GET/POST请求,表达式解析计算。

作者: ntestoc

Created: 2019-06-10 周一 16:48

原文地址:https://www.cnblogs.com/ntestoc/p/10997899.html