add notes

This commit is contained in:
Daniel Bulant 2025-03-29 22:07:37 +01:00
parent 2f4a2eb397
commit f110e7746b
No known key found for this signature in database
17 changed files with 337 additions and 129 deletions

View file

@ -36,6 +36,7 @@
<!-- <Button text on:click={toggle}>{$darkmode ? "Light" : "Dark"} mode</Button> -->
<div class="big">
<Button text href="/#contact" class="big">Contact</Button>
<Button text href="/notes" class="big">Notes</Button>
<Button text href="/posts" class="big">Blog</Button>
</div>
</div>

View file

@ -18,6 +18,11 @@
export let categories;
export let bigThumbnail;
export let thumbnail;
export let data;
let isPost = data.url.includes("/posts/");
$: isPost = data.url.includes("/posts/");
let dt = DateTime.fromISO(date);
$: dt = DateTime.fromISO(date);
@ -50,14 +55,19 @@
</svelte:head>
<main class="post-layout">
<span><a href="/posts">Posts</a> /</span>
{#if isPost}
<span><a href="/posts">Posts</a> /</span>
{:else}
<span><a href="/notes">Notes</a> /</span>
{/if}
<h1>{title}</h1>
<div class="flex justify-between flex-wrap">
<span>Written {dt.toRelativeCalendar()} ({dt.toLocaleString(DateTime.DATE_FULL)})</span>
<div class="flex justify-between flex-wrap pt-2">
{#if date}
<span>Written {dt.toRelativeCalendar()} ({dt.toLocaleString(DateTime.DATE_FULL)})</span>
{/if}
{#if dtu}
<span>Updated {dtu.toRelativeCalendar()} ({dtu.toLocaleString(DateTime.DATE_FULL)})</span>
{/if}
<!-- <span>{categories.join(", ")}</span> -->
</div>
<slot />
<noscript><hr>Although the page mostly works without Javascript, you won't be able to comment. Also, I acknowledge the privacy flaws, but Javascript is a fundamental part of modern web, and shouldn't be disabled. Maybe use an adblock instead of disabling it for everything?</noscript>
@ -65,7 +75,7 @@
repo="danbulant/design"
issue-term="pathname"
label="comment"
theme="github-{$darkmode ? "dark" : "light"}"
theme="github-dark"
crossorigin="anonymous"
async>
</script>
@ -166,7 +176,7 @@
@apply rounded-lg bg-dark-400/03 p-1 transition-colors duration-300;
}
:global(body .post-layout ul) {
@apply list-disc list-inside;
@apply list-disc mx-4;
}
:global(body .post-layout ul li) {
@apply my-0.5;

View file

@ -29,7 +29,7 @@
<!-- HTML Entity encoded email -->
<p class="text-center">I'm sorry for that. If this is a repeated problem, try contacting me (me@danbulant.eu)</p>
<div class="flex justify-center">
<div class="flex justify-center mt-4">
<Button href="/">Go to my home page</Button>
</div>

View file

@ -1,7 +1,5 @@
/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
return {
posts: await fetch("/api/posts.json").then(t => t.json())
};
return await fetch("/api/posts.json").then(t => t.json())
}

View file

@ -47,9 +47,12 @@
</span>
</Button>
<div class="right md:inline-block hidden p-4 border-l-2 border-l-white/20">
{#if selectedPost}
<!-- {#if selectedPost}
<a href={selectedPost.path}><b>{selectedPost.title}</b></a>
{/if}
{/if} -->
<a href="/notes">
<b>New 'notes' section.</b>
</a>
</div>
</div>
</div>

View file

@ -1,11 +1,8 @@
/**
* @type {import("@sveltejs/kit").RequestHandler}
*/
export async function GET(req) {
const allPostFiles = import.meta.glob('../../posts/**/*.md');
import { json } from "@sveltejs/kit";
const allPosts = (await Promise.all(
Object.entries(allPostFiles).map(async ([path, resolver]) => {
function loadAll(files) {
return Promise.all(
Object.entries(files).map(async ([path, resolver]) => {
const { metadata } = await resolver();
let postPath = path.slice(2, -3);
if(postPath.endsWith('/+page')) postPath = postPath.slice(0, -6);
@ -14,17 +11,27 @@ export async function GET(req) {
path: postPath,
};
})
)).filter(t => !t.draft);
)
}
/**
* @type {import("@sveltejs/kit").RequestHandler}
*/
export async function GET(req) {
const allPostFiles = import.meta.glob('../../posts/**/*.md');
const allNotesFiles = import.meta.glob('../../notes/**/*.md');
const allPosts = (await loadAll(allPostFiles)).filter(t => !t.draft);
const allNotes = (await loadAll(allNotesFiles));
allPosts.sort((a, b) => {
return new Date(b.date) - new Date(a.date)
});
return new Response(JSON.stringify(allPosts.filter(t => new Date(t.date) < Date.now())), {
headers: {
'Content-Type': 'application/json'
}
});
return json({
posts: allPosts.filter(t => new Date(t.date) < Date.now()),
notes: allNotes
})
}
export const prerender = true;

11
src/routes/notes/+page.js Normal file
View file

@ -0,0 +1,11 @@
import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
const response = await fetch("/api/posts.json");
if(!response.ok) {
throw error(response.statusText, response.status);
}
return response.json();
}

View file

@ -0,0 +1,11 @@
<script>
import Posts from "../posts/posts.svelte";
export var data;
var posts = data.posts;
$: posts = data.posts;
var notes = data.notes;
$: notes = data.notes;
</script>
<Posts {posts} {notes} postsActive={false} />

View file

@ -0,0 +1,24 @@
---
title: Crypto challenges and analysis
tags: [security]
date: 2025-03-29
---
I'm not much of a crypto guy so there won't be that many separate notes.
## Transposition
- letter counts will be similar to real language (how often a letter shows up in the text)
- you can use letter count table to solve these challenges
## S box
Substition box. Used in diagrams for more advanced ciphers, used for mixing up data (so that data in byte 1 moves to byte 7 and so on)
## DES
56bit key (chosen not to make it too secure).
## 3DES
Trides, encrypts, decrypts and encrypts again. If a single key is provided, try it for all 3 (becomes just slower DES).

View file

@ -0,0 +1,18 @@
---
title: File analysis tools + enumeration
tags: [security]
date: 2025-03-29
---
- `file` shows filetype.
- `binwalk` finds file headers inside of file. Can be used to extract data from corrupted disk images.
- `7z` can extract almost anything.
- `foremost` data recovery tool.
- `volatility` for RAM analysis (mainly windows).
- `ffuf` (web) fuzzer
- `hydra` credential stuffer
- `sqlmap` for automatic SQL injection exploiting
- `linPEAS`, `linEnum`, `lse`, `find` for finding executables.
- `find -perm 4000` to filter by perm (4000 suid, 2000 guid, sum for both)
- `find -user root` to filter by user

View file

@ -0,0 +1,15 @@
---
title: Mimikatz on linux
tags: [security]
date: 2025-03-29
---
*pypykatz* is a Python library to parse credentials from Windows Security. Pypykatz is portable, unlike mimikatz which requires windows to run.
SUID is the users secure id. Usually the name of their folder in AppData (S-1-5-21-...). Certain password hashes (I think SHA1) can be used instead of plaintext, see pypykatz/mimikatz docs.
```bash
pypykatz dpapi prekey password <SUID> <password in plaintext> -o prekeys
pypykatz dpapi masterkey <SUID> <path to prekeys> -o masterkeys
pypykatz dpapi chrome <masterkey> <path to chrome local state> --logindata <path to login data /Default/Login\ Data> --cookies <path to cookies /Default/Network/Cookies>
```

View file

@ -0,0 +1,37 @@
---
title: MySQL, express, and the importance of types
tags: [security, javascript]
date: 2025-03-29
---
TLDR object serialization via [sqlstring](https://www.npmjs.com/package/sqlstring), vulnerable if user input is not primitive (e.g. unchecked object).
```js
const app = express()
const db = await mysql.createConnection({ ... })
app.get("/", (req, res) => {
// unsafety here :)
let users = await db.query("SELECT * FROM table WHERE name = ?", [req.query.name])
res.json(users)
})
```
*There's no way to prevent this, says only language where this regularly happens*
SQL Injection is bad! Use a library to prevent SQL Injection!
Nowhere in [MySQL2 docs](https://sidorares.github.io/node-mysql2/docs) does it mention that objects are serialized into SQL (Note that this may have changed - this is more of a guide for testing vulns / ctf challenges than a bug report, this is not new research). Via dependencies, you can find it uses [sqlstring](https://www.npmjs.com/package/sqlstring). That does mention that it does object serialization:
```js
var post = {id: 1, title: 'Hello MySQL'};
var sql = SqlString.format('INSERT INTO posts SET ?', post);
console.log(sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
```
But wait! Query is surely just string?
No
Express parses query string like `name[obj]=val`. And MySQL accepts `1 = 1 = 1`. Also, people often allow both urlencoded and json as input, even if their pages use urlencoded forms, so try submitting a JSON body with a similar payload.
This is based on [previous research](https://flatt.tech/research/posts/finding-an-unseen-sql-injection-by-bypassing-escape-functions-in-mysqljs-mysql/) and solving a CTF challenge. I get reminded of it every few months by reading another project which uses mysql2 and express. I do not support using express from a technical view - it is full of surpises, took really long to get promises support (so long that most libraries based on express still don't support it), and is actually the slowest of the commonly used frameworks.

View file

@ -0,0 +1,11 @@
---
title: Unpacking packed nodejs
tags: [cybersec]
date: 2025-03-29
---
Use [pkg unpacker](https://github.com/LockBlock-dev/pkg-unpacker). Some applications are compiled with (now deprecated) [vercel/pkg](https://github.com/vercel/pkg). Those work by embedding packed code into nodejs statically compiled executable. This tool unpacks those files into separate files for readability.
Note that pkg has support for v8 bytecode only mode (afaik it's used by default for dependencies, but apps in the wild have it disabled for their source code too), and that is very difficult to reliable reverse engineer - the bytecode is not stable between releases, and there isn't a ton of tools for analysing different versions, and they often rely on compiling parts of chromium/v8.
As for node SEA, the recommended alternative for pkg, use `strings -t x` (`-t x` for hexadecimal offsets, `-t d` for decimal) and find the text in your favorite hex editor. It is not the default there to have v8 bytecode only.

View file

@ -0,0 +1,11 @@
---
title: "Micronotes: Write your knowledge"
tags: [general]
date: 2025-03-29
---
You won't remember everything. Use micro notes if lazy. Publish them should you wish to share (you should!), don't if you do not. But write your knowledge.
This is my collection of notes, mainly for tech purposes, like solving programming issues, CTF write-ups and more. Majority of them won't bring anything new to the world, though they were once new to me, and I don't wish to have to research them all again, I want to research new ideas instead.
Perhaps I'll rewrite some of those notes into full fledged posts. For now, these remain just short, dense notes. This is a call to make your own hacktricks.

View file

@ -1,9 +1,11 @@
import { error } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
const response = await fetch("/api/posts.json");
if(!response.ok) {
throw error(response.statusText, response.status);
}
return {
posts: response.ok && (await response.json())
};
return response.json();
}

View file

@ -1,108 +1,11 @@
<script>
import HeroPost from "$lib/components/heroPost.svelte";
import Post from "$lib/components/post.svelte";
import { flip } from 'svelte/animate';
import Posts from "./posts.svelte";
var currentHover = null;
export var data;
var posts = data.posts;
$: posts = data.posts;
var tags = posts && posts.map(t => t.categories).flat().filter((t, i, a) => a.indexOf(t) == i).sort();
var selectedTags = [];
function toggle(tag) {
if(selectedTags.includes(tag)) {
selectedTags = selectedTags.filter(t => t != tag);
} else {
selectedTags.push(tag);
selectedTags = selectedTags;
}
}
var filteredPosts = selectedTags ? posts.slice(1).filter(post => !selectedTags.length || selectedTags.find(tag => post.categories.includes(tag))) : posts.slice(1);
$: filteredPosts = selectedTags ? posts.slice(1).filter(post => !selectedTags.length || selectedTags.find(tag => post.categories.includes(tag))) : posts.slice(1);
var notes = data.notes;
$: notes = data.notes;
</script>
<svelte:head>
<title>Blog - Daniel Bulant</title>
<link href="/posts/rss.xml" type="application/rss+xml" rel="alternate" title="Blog posts - RSS" />
<meta name="description" content="My personal blog about work, programming and fun stuff.">
<meta property="og:site_name" content="Daniel Bulant"/>
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="profile" />
<meta property="og:profile:first_name" content="Daniel" />
<meta property="og:profile:last_name" content="Bulant" />
<meta property="og:profile:username" content="danbulant" />
<meta property="og:profile:gender" content="male" />
</svelte:head>
<div class="parent md:flex max-w-screen">
<h1 class="md:hidden">Posts</h1>
<div class="posts">
<h1 class="hidden md:block">
Posts
<small>
<a href="/posts/rss.xml" class="rss">
<img src="/rss-icon.svg" alt="RSS icon" />
RSS
</a>
</small>
</h1>
{#if !selectedTags.length || selectedTags.find(tag => posts[0].categories.includes(tag))}
<HeroPost {...posts[0]} />
<hr>
{/if}
{#each filteredPosts as post (post.title)}
<div animate:flip={{ duration: 250 }}>
<Post {...post} bind:currentHover />
</div>
{/each}
</div>
</div>
<style lang="postcss">
.parent {
@apply pt-10 w-max m-auto px-5 gap-5;
}
.posts {
@apply max-w-2xl;
}
@media (min-width: 42rem) {
.posts {
@apply w-2xl;
}
}
h1 {
@apply m-0 mb-1 p-0 font-bold text-3xl;
}
hr {
height: 1px;
border: none;
background: black;
}
:global(.dark) hr {
background: white;
}
small {
text-align: center;
width: 100%;
margin: 30px 0;
}
small a, .rss {
color: rgb(4, 192, 192)
}
.rss {
@apply pl-4 text-sm;
}
.rss img {
@apply inline mr-1 w-4 h-4;
}
</style>
<Posts {posts} {notes} postsActive />

View file

@ -0,0 +1,146 @@
<script>
import HeroPost from "$lib/components/heroPost.svelte";
import Post from "$lib/components/post.svelte";
import { flip } from 'svelte/animate';
var currentHover = null;
export var posts
export var notes
var tags = posts && posts.map(t => t.categories).flat().filter((t, i, a) => a.indexOf(t) == i).sort();
var selectedTags = [];
function toggle(tag) {
if(selectedTags.includes(tag)) {
selectedTags = selectedTags.filter(t => t != tag);
} else {
selectedTags.push(tag);
selectedTags = selectedTags;
}
}
export let postsActive = true;
var filteredPosts = selectedTags ? posts.slice(1).filter(post => !selectedTags.length || selectedTags.find(tag => post.categories.includes(tag))) : posts.slice(1);
$: filteredPosts = selectedTags ? posts.slice(1).filter(post => !selectedTags.length || selectedTags.find(tag => post.categories.includes(tag))) : posts.slice(1);
</script>
<svelte:head>
<title>{postsActive ? 'Blog' : 'Notes'} - Daniel Bulant</title>
<link href="/posts/rss.xml" type="application/rss+xml" rel="alternate" title="Blog posts - RSS" />
<meta name="description" content="My personal blog about work, programming and fun stuff.">
<meta property="og:site_name" content="Daniel Bulant"/>
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="profile" />
<meta property="og:profile:first_name" content="Daniel" />
<meta property="og:profile:last_name" content="Bulant" />
<meta property="og:profile:username" content="danbulant" />
<meta property="og:profile:gender" content="male" />
</svelte:head>
<div class="parent md:w-max w-full md:flex max-w-screen">
<div class="tabs md:hidden flex">
<div class="tab" class:active={postsActive} on:click={() => postsActive = true}>Posts</div>
<div class="tab" class:active={!postsActive} on:click={() => postsActive = false}>Notes</div>
</div>
<div class="posts md:block" class:hidden={!postsActive}>
<h1 class="hidden md:block">
Posts
<small>
<a href="/posts/rss.xml" class="rss">
<img src="/rss-icon.svg" alt="RSS icon" />
RSS
</a>
</small>
</h1>
{#if !selectedTags.length || selectedTags.find(tag => posts[0].categories.includes(tag))}
<HeroPost {...posts[0]} />
<hr>
{/if}
{#each filteredPosts as post (post.title)}
<div animate:flip={{ duration: 250 }}>
<Post {...post} bind:currentHover />
</div>
{/each}
</div>
<div class="notes md:block" class:hidden={postsActive}>
<h2 class="md:text-2xl">Notes</h2>
<p>Collection of short notes, write-ups and not-yet-posts.</p>
<ul>
{#each notes as note}
<li>
<a href={note.path}>
{note.title}
</a>
</li>
{/each}
</ul>
</div>
</div>
<style lang="postcss">
.tabs {
@apply gap-5;
}
.tab {
@apply text-lg cursor-pointer text-gray-500;
}
.tab.active {
@apply text-white font-bold border-b select-none;
}
ul {
@apply list-disc pl-5 my-4;
}
li {
@apply mb-2;
}
.parent {
@apply pt-10 m-auto px-5 gap-5;
}
.posts {
@apply max-w-2xl;
}
h2 {
@apply m-0 mb-1 p-0 font-bold text-3xl;
}
@media (min-width: 42rem) {
.posts {
@apply w-2xl;
}
}
h1 {
@apply m-0 mb-1 p-0 font-bold text-3xl;
}
hr {
@apply mt-1;
height: 1px;
border: none;
background: black;
}
:global(.dark) hr {
background: rgb(136, 136, 136);
}
small {
text-align: center;
width: 100%;
margin: 30px 0;
}
small a, .rss {
color: rgb(4, 192, 192)
}
.rss {
@apply pl-4 text-sm;
}
.rss img {
@apply inline mr-1 w-4 h-4;
}
</style>